Дозаливка

This commit is contained in:
2022-12-19 22:22:19 +02:00
parent 73d69cb0ae
commit 2f6517f5b3
22083 changed files with 494007 additions and 0 deletions
@@ -0,0 +1,174 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Config Authentication plugin for phpMyAdmin
*
* @package PhpMyAdmin-Authentication
* @subpackage Config
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/* Get the authentication interface */
require_once 'libraries/plugins/AuthenticationPlugin.class.php';
/**
* Handles the config authentication method
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationConfig extends AuthenticationPlugin
{
/**
* Displays authentication form
*
* @return boolean always true
*/
public function auth()
{
return true;
}
/**
* Gets advanced authentication settings
*
* @return boolean always true
*/
public function authCheck()
{
return true;
}
/**
* Set the user and password after last checkings if required
*
* @return boolean always true
*/
public function authSetUser()
{
return true;
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* @global string the MySQL error message PHP returns
* @global string the connection type (persistent or not)
* @global string the MySQL server port to use
* @global string the MySQL socket port to use
* @global array the current server settings
* @global string the font face to use in case of failure
* @global string the default font size to use in case of failure
* @global string the big font size to use in case of failure
* @global boolean tell the "PMA_mysqlDie()" function headers have been
* sent
*
* @return boolean always true (no return indeed)
*/
public function authFails()
{
$conn_error = $GLOBALS['dbi']->getError();
if (! $conn_error) {
$conn_error = __('Cannot connect: invalid settings.');
}
/* HTML header */
$response = PMA_Response::getInstance();
$response->getFooter()->setMinimal();
$header = $response->getHeader();
$header->setBodyId('loginform');
$header->setTitle(__('Access denied'));
$header->disableMenu();
echo '<br /><br />
<center>
<h1>';
echo sprintf(__('Welcome to %s'), ' phpMyAdmin ');
echo '</h1>
</center>
<br />
<table cellpadding="0" cellspacing="3" style="margin: 0 auto" width="80%">
<tr>
<td>';
if (isset($GLOBALS['allowDeny_forbidden'])
&& $GLOBALS['allowDeny_forbidden']
) {
trigger_error(__('Access denied'), E_USER_NOTICE);
} else {
// Check whether user has configured something
if ($GLOBALS['PMA_Config']->source_mtime == 0) {
echo '<p>' . sprintf(
__(
'You probably did not create a configuration file.'
. ' You might want to use the %1$ssetup script%2$s to'
. ' create one.'
),
'<a href="setup/">',
'</a>'
) . '</p>' . "\n";
} elseif (! isset($GLOBALS['errno'])
|| (isset($GLOBALS['errno']) && $GLOBALS['errno'] != 2002)
&& $GLOBALS['errno'] != 2003
) {
// if we display the "Server not responding" error, do not confuse
// users by telling them they have a settings problem
// (note: it's true that they could have a badly typed host name,
// but anyway the current message tells that the server
// rejected the connection, which is not really what happened)
// 2002 is the error given by mysqli
// 2003 is the error given by mysql
trigger_error(
__(
'phpMyAdmin tried to connect to the MySQL server, and the'
. ' server rejected the connection. You should check the'
. ' host, username and password in your configuration and'
. ' make sure that they correspond to the information given'
. ' by the administrator of the MySQL server.'
), E_USER_WARNING
);
}
echo PMA_Util::mysqlDie(
$conn_error, '', true, '', false
);
}
$GLOBALS['error_handler']->dispUserErrors();
echo '</td>
</tr>
<tr>
<td>' . "\n";
echo '<a href="'
. $GLOBALS['cfg']['DefaultTabServer']
. PMA_URL_getCommon(array()) . '" class="button disableAjax">'
. __('Retry to connect')
. '</a>' . "\n";
echo '</td>
</tr>' . "\n";
if (count($GLOBALS['cfg']['Servers']) > 1) {
// offer a chance to login to other servers if the current one failed
include_once './libraries/select_server.lib.php';
echo '<tr>' . "\n";
echo ' <td>' . "\n";
echo PMA_selectServer(true, true);
echo ' </td>' . "\n";
echo '</tr>' . "\n";
}
echo '</table>' . "\n";
if (!defined('TESTSUITE')) {
exit;
}
return true;
}
/**
* This method is called when any PluginManager to which the observer
* is attached calls PluginManager::notify()
*
* @param SplSubject $subject The PluginManager notifying the observer
* of an update.
*
* @return void
*/
public function update (SplSubject $subject)
{
}
}
@@ -0,0 +1,817 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Cookie Authentication plugin for phpMyAdmin
*
* @package PhpMyAdmin-Authentication
* @subpackage Cookie
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/* Get the authentication interface */
require_once 'libraries/plugins/AuthenticationPlugin.class.php';
/**
* Remember where to redirect the user
* in case of an expired session.
*/
if (! empty($_REQUEST['target'])) {
$GLOBALS['target'] = $_REQUEST['target'];
} else if (PMA_getenv('SCRIPT_NAME')) {
$GLOBALS['target'] = basename(PMA_getenv('SCRIPT_NAME'));
}
/**
* Swekey authentication functions.
*/
require './libraries/plugins/auth/swekey/swekey.auth.lib.php';
/**
* Initialization
* Store the initialization vector because it will be needed for
* further decryption. I don't think necessary to have one iv
* per server so I don't put the server number in the cookie name.
*/
if (function_exists('mcrypt_encrypt')) {
if (empty($_COOKIE['pma_mcrypt_iv'])
|| ! ($iv = base64_decode($_COOKIE['pma_mcrypt_iv'], true))
) {
srand((double) microtime() * 1000000);
$td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '');
if ($td === false) {
PMA_fatalError(__('Failed to use Blowfish from mcrypt!'));
}
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$GLOBALS['PMA_Config']->setCookie(
'pma_mcrypt_iv',
base64_encode($iv)
);
}
}
/**
* Handles the cookie authentication method
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationCookie extends AuthenticationPlugin
{
/**
* Displays authentication form
*
* this function MUST exit/quit the application
*
* @global string $conn_error the last connection error
*
* @return boolean|void
*/
public function auth()
{
global $conn_error;
$response = PMA_Response::getInstance();
if ($response->isAjax()) {
$response->isSuccess(false);
$login_link = '<br /><br />[ ' .
sprintf(
'<a href="%s" class="ajax login-link">%s</a>',
$GLOBALS['cfg']['PmaAbsoluteUri'],
__('Log in')
)
. ' ]';
if (! empty($conn_error)) {
$conn_error .= $login_link;
$response->addJSON(
'message',
PMA_Message::error(
$conn_error
)
);
} else {
$response->addJSON(
'message',
PMA_Message::error(
__('Your session has expired. Please log in again.') .
$login_link
)
);
}
if (defined('TESTSUITE')) {
return true;
} else {
exit;
}
}
/* Perform logout to custom URL */
if (! empty($_REQUEST['old_usr'])
&& ! empty($GLOBALS['cfg']['Server']['LogoutURL'])
) {
PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']);
if (defined('TESTSUITE')) {
return true;
} else {
exit;
}
}
// No recall if blowfish secret is not configured as it would produce
// garbage
if ($GLOBALS['cfg']['LoginCookieRecall']
&& ! empty($GLOBALS['cfg']['blowfish_secret'])
) {
$default_user = $GLOBALS['PHP_AUTH_USER'];
$default_server = $GLOBALS['pma_auth_server'];
$autocomplete = '';
} else {
$default_user = '';
$default_server = '';
// skip the IE autocomplete feature.
$autocomplete = ' autocomplete="off"';
}
$response->getFooter()->setMinimal();
$header = $response->getHeader();
$header->setBodyId('loginform');
$header->setTitle('phpMyAdmin');
$header->disableMenu();
$header->disableWarnings();
if (file_exists(CUSTOM_HEADER_FILE)) {
include CUSTOM_HEADER_FILE;
}
echo '
<div class="container">
<a href="';
echo PMA_linkURL('http://www.phpmyadmin.net/');
echo '" target="_blank" class="logo">';
$logo_image = $GLOBALS['pmaThemeImage'] . 'logo_right.png';
if (@file_exists($logo_image)) {
echo '<img src="' . $logo_image
. '" id="imLogo" name="imLogo" alt="phpMyAdmin" border="0" />';
} else {
echo '<img name="imLogo" id="imLogo" src="'
. $GLOBALS['pmaThemeImage'] . 'pma_logo.png' . '" '
. 'border="0" width="88" height="31" alt="phpMyAdmin" />';
}
echo '</a>
<h1>';
echo sprintf(
__('Welcome to %s'),
'<bdo dir="ltr" lang="en">phpMyAdmin</bdo>'
);
echo "</h1>";
// Show error message
if (! empty($conn_error)) {
PMA_Message::rawError($conn_error)->display();
}
echo "<noscript>\n";
PMA_message::error(
__("Javascript must be enabled past this point")
)->display();
echo "</noscript>\n";
echo "<div class='hide js-show'>";
// Displays the languages form
if (empty($GLOBALS['cfg']['Lang'])) {
include_once './libraries/display_select_lang.lib.php';
// use fieldset, don't show doc link
echo PMA_getLanguageSelectorHtml(true, false);
}
echo '</div>
<br />
<!-- Login form -->
<form method="post" action="index.php" name="login_form"' . $autocomplete .
' class="disableAjax login hide js-show">
<fieldset>
<legend>';
echo __('Log in');
echo PMA_Util::showDocu('index');
echo '</legend>';
if ($GLOBALS['cfg']['AllowArbitraryServer']) {
echo '
<div class="item">
<label for="input_servername" title="';
echo __(
'You can enter hostname/IP address and port separated by space.'
);
echo '">';
echo __('Server:');
echo '</label>
<input type="text" name="pma_servername" id="input_servername"';
echo ' value="';
echo htmlspecialchars($default_server);
echo '" size="24" class="textfield" title="';
echo __(
'You can enter hostname/IP address and port separated by space.'
); echo '" />
</div>';
}
echo '<div class="item">
<label for="input_username">' . __('Username:') . '</label>
<input type="text" name="pma_username" id="input_username" '
. 'value="' . htmlspecialchars($default_user) . '" size="24"'
. ' class="textfield"/>
</div>
<div class="item">
<label for="input_password">' . __('Password:') . '</label>
<input type="password" name="pma_password" id="input_password"'
. ' value="" size="24" class="textfield" />
</div>';
if (count($GLOBALS['cfg']['Servers']) > 1) {
echo '<div class="item">
<label for="select_server">' . __('Server Choice:') .'</label>
<select name="server" id="select_server"';
if ($GLOBALS['cfg']['AllowArbitraryServer']) {
echo ' onchange="document.forms[\'login_form\'].'
. 'elements[\'pma_servername\'].value = \'\'" ';
}
echo '>';
include_once './libraries/select_server.lib.php';
echo PMA_selectServer(false, false);
echo '</select></div>';
} else {
echo ' <input type="hidden" name="server" value="'
. $GLOBALS['server'] . '" />';
} // end if (server choice)
// We already have one correct captcha.
$skip = false;
if ( isset($_SESSION['last_valid_captcha'])
&& $_SESSION['last_valid_captcha']
) {
$skip = true;
}
// Add captcha input field if reCaptcha is enabled
if ( !empty($GLOBALS['cfg']['CaptchaLoginPrivateKey'])
&& !empty($GLOBALS['cfg']['CaptchaLoginPublicKey'])
&& !$skip
) {
// If enabled show captcha to the user on the login screen.
echo '<script type="text/javascript"
src="https://www.google.com/recaptcha/api/challenge?'
. 'k=' . $GLOBALS['cfg']['CaptchaLoginPublicKey'] . '&amp;'
. 'hl=' . $GLOBALS['lang'] . '">
</script>
<noscript>
<iframe src="https://www.google.com/recaptcha/api/noscript?k='
. $GLOBALS['cfg']['CaptchaLoginPublicKey'] . '"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40">
</textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>
<script type="text/javascript">
$("#recaptcha_reload_btn").addClass("disableAjax");
$("#recaptcha_switch_audio_btn").addClass("disableAjax");
$("#recaptcha_switch_img_btn").addClass("disableAjax");
$("#recaptcha_whatsthis_btn").addClass("disableAjax");
$("#recaptcha_audio_play_again").live("mouseover", function() {
$(this).addClass("disableAjax");
});
</script>';
}
echo '</fieldset>
<fieldset class="tblFooters">
<input value="' . __('Go') . '" type="submit" id="input_go" />';
$_form_params = array();
if (! empty($GLOBALS['target'])) {
$_form_params['target'] = $GLOBALS['target'];
}
if (! empty($GLOBALS['db'])) {
$_form_params['db'] = $GLOBALS['db'];
}
if (! empty($GLOBALS['table'])) {
$_form_params['table'] = $GLOBALS['table'];
}
// do not generate a "server" hidden field as we want the "server"
// drop-down to have priority
echo PMA_URL_getHiddenInputs($_form_params, '', 0, 'server');
echo '</fieldset>
</form>';
// BEGIN Swekey Integration
Swekey_login('input_username', 'input_go');
// END Swekey Integration
if ($GLOBALS['error_handler']->hasDisplayErrors()) {
echo '<div>';
$GLOBALS['error_handler']->dispErrors();
echo '</div>';
}
echo '</div>';
if (file_exists(CUSTOM_FOOTER_FILE)) {
include CUSTOM_FOOTER_FILE;
}
if (! defined('TESTSUITE')) {
exit;
} else {
return true;
}
}
/**
* Gets advanced authentication settings
*
* this function DOES NOT check authentication - it just checks/provides
* authentication credentials required to connect to the MySQL server
* usually with $GLOBALS['dbi']->connect()
*
* it returns false if something is missing - which usually leads to
* auth() which displays login form
*
* it returns true if all seems ok which usually leads to auth_set_user()
*
* it directly switches to authFails() if user inactivity timout is reached
*
* @todo AllowArbitraryServer on does not imply that the user wants an
* arbitrary server, or? so we should also check if this is filled
* and not only if allowed
*
* @return boolean whether we get authentication settings or not
*/
public function authCheck()
{
global $conn_error;
// Initialization
/**
* @global $GLOBALS['pma_auth_server'] the user provided server to
* connect to
*/
$GLOBALS['pma_auth_server'] = '';
$GLOBALS['PHP_AUTH_USER'] = $GLOBALS['PHP_AUTH_PW'] = '';
$GLOBALS['from_cookie'] = false;
// BEGIN Swekey Integration
if (! Swekey_Auth_check()) {
return false;
}
// END Swekey Integration
if (defined('PMA_CLEAR_COOKIES')) {
foreach ($GLOBALS['cfg']['Servers'] as $key => $val) {
$GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key);
$GLOBALS['PMA_Config']->removeCookie('pmaServer-' . $key);
$GLOBALS['PMA_Config']->removeCookie('pmaUser-' . $key);
}
return false;
}
// We already have one correct captcha.
$skip = false;
if ( isset($_SESSION['last_valid_captcha'])
&& $_SESSION['last_valid_captcha']
) {
$skip = true;
}
// Verify Captcha if it is required.
if ( !empty($GLOBALS['cfg']['CaptchaLoginPrivateKey'])
&& !empty($GLOBALS['cfg']['CaptchaLoginPublicKey'])
&& !$skip
) {
if ( !empty($_POST["recaptcha_challenge_field"])
&& !empty($_POST["recaptcha_response_field"])
) {
include_once 'libraries/plugins/auth/recaptchalib.php';
// Use private key to verify captcha status.
$resp = recaptcha_check_answer(
$GLOBALS['cfg']['CaptchaLoginPrivateKey'],
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]
);
// Check if the captcha entered is valid, if not stop the login.
if ( !$resp->is_valid ) {
$conn_error = __('Entered captcha is wrong, try again!');
$_SESSION['last_valid_captcha'] = false;
return false;
} else {
$_SESSION['last_valid_captcha'] = true;
}
} elseif (! empty($_POST["recaptcha_challenge_field"])
&& empty($_POST["recaptcha_response_field"])
) {
$conn_error = __('Please enter correct captcha!');
return false;
} else {
if (! isset($_SESSION['last_valid_captcha'])
|| ! $_SESSION['last_valid_captcha']
) {
return false;
}
}
}
if (! empty($_REQUEST['old_usr'])) {
// The user wants to be logged out
// -> delete his choices that were stored in session
// according to the PHP manual we should do this before the destroy:
//$_SESSION = array();
if (! defined('TESTSUITE')) {
session_destroy();
// $_SESSION array is not immediately emptied
$_SESSION['last_valid_captcha'] = false;
}
// -> delete password cookie(s)
if ($GLOBALS['cfg']['LoginCookieDeleteAll']) {
foreach ($GLOBALS['cfg']['Servers'] as $key => $val) {
$GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key);
if (isset($_COOKIE['pmaPass-' . $key])) {
unset($_COOKIE['pmaPass-' . $key]);
}
}
} else {
$GLOBALS['PMA_Config']->removeCookie(
'pmaPass-' . $GLOBALS['server']
);
if (isset($_COOKIE['pmaPass-' . $GLOBALS['server']])) {
unset($_COOKIE['pmaPass-' . $GLOBALS['server']]);
}
}
}
if (! empty($_REQUEST['pma_username'])) {
// The user just logged in
$GLOBALS['PHP_AUTH_USER'] = $_REQUEST['pma_username'];
$GLOBALS['PHP_AUTH_PW'] = empty($_REQUEST['pma_password'])
? ''
: $_REQUEST['pma_password'];
if ($GLOBALS['cfg']['AllowArbitraryServer']
&& isset($_REQUEST['pma_servername'])
) {
$GLOBALS['pma_auth_server'] = $_REQUEST['pma_servername'];
}
return true;
}
// At the end, try to set the $GLOBALS['PHP_AUTH_USER']
// and $GLOBALS['PHP_AUTH_PW'] variables from cookies
// servername
if ($GLOBALS['cfg']['AllowArbitraryServer']
&& ! empty($_COOKIE['pmaServer-' . $GLOBALS['server']])
) {
$GLOBALS['pma_auth_server']
= $_COOKIE['pmaServer-' . $GLOBALS['server']];
}
// username
if (empty($_COOKIE['pmaUser-' . $GLOBALS['server']])) {
return false;
}
$GLOBALS['PHP_AUTH_USER'] = $this->blowfishDecrypt(
$_COOKIE['pmaUser-' . $GLOBALS['server']],
$this->_getBlowfishSecret()
);
// user was never logged in since session start
if (empty($_SESSION['last_access_time'])) {
return false;
}
// User inactive too long
$last_access_time = time() - $GLOBALS['cfg']['LoginCookieValidity'];
if ($_SESSION['last_access_time'] < $last_access_time
) {
PMA_Util::cacheUnset('is_create_db_priv', true);
PMA_Util::cacheUnset('is_process_priv', true);
PMA_Util::cacheUnset('is_reload_priv', true);
PMA_Util::cacheUnset('db_to_create', true);
PMA_Util::cacheUnset('dbs_where_create_table_allowed', true);
$GLOBALS['no_activity'] = true;
$this->authFails();
if (! defined('TESTSUITE')) {
exit;
} else {
return false;
}
}
// password
if (empty($_COOKIE['pmaPass-' . $GLOBALS['server']])) {
return false;
}
$GLOBALS['PHP_AUTH_PW'] = $this->blowfishDecrypt(
$_COOKIE['pmaPass-' . $GLOBALS['server']],
$this->_getBlowfishSecret()
);
if ($GLOBALS['PHP_AUTH_PW'] == "\xff(blank)") {
$GLOBALS['PHP_AUTH_PW'] = '';
}
$GLOBALS['from_cookie'] = true;
return true;
}
/**
* Set the user and password after last checkings if required
*
* @return boolean always true
*/
public function authSetUser()
{
global $cfg;
// Ensures valid authentication mode, 'only_db', bookmark database and
// table names and relation table name are used
if ($cfg['Server']['user'] != $GLOBALS['PHP_AUTH_USER']) {
foreach ($cfg['Servers'] as $idx => $current) {
if ($current['host'] == $cfg['Server']['host']
&& $current['port'] == $cfg['Server']['port']
&& $current['socket'] == $cfg['Server']['socket']
&& $current['ssl'] == $cfg['Server']['ssl']
&& $current['connect_type'] == $cfg['Server']['connect_type']
&& $current['user'] == $GLOBALS['PHP_AUTH_USER']
) {
$GLOBALS['server'] = $idx;
$cfg['Server'] = $current;
break;
}
} // end foreach
} // end if
if ($GLOBALS['cfg']['AllowArbitraryServer']
&& ! empty($GLOBALS['pma_auth_server'])
) {
/* Allow to specify 'host port' */
$parts = explode(' ', $GLOBALS['pma_auth_server']);
if (count($parts) == 2) {
$tmp_host = $parts[0];
$tmp_port = $parts[1];
} else {
$tmp_host = $GLOBALS['pma_auth_server'];
$tmp_port = '';
}
if ($cfg['Server']['host'] != $GLOBALS['pma_auth_server']) {
$cfg['Server']['host'] = $tmp_host;
if (! empty($tmp_port)) {
$cfg['Server']['port'] = $tmp_port;
}
}
unset($tmp_host, $tmp_port, $parts);
}
$cfg['Server']['user'] = $GLOBALS['PHP_AUTH_USER'];
$cfg['Server']['password'] = $GLOBALS['PHP_AUTH_PW'];
// Avoid showing the password in phpinfo()'s output
unset($GLOBALS['PHP_AUTH_PW']);
unset($_SERVER['PHP_AUTH_PW']);
$_SESSION['last_access_time'] = time();
}
/**
* Stores user credentials after successful login.
*
* @return void
*/
public function storeUserCredentials()
{
global $cfg;
// Name and password cookies need to be refreshed each time
// Duration = one month for username
$GLOBALS['PMA_Config']->setCookie(
'pmaUser-' . $GLOBALS['server'],
$this->blowfishEncrypt(
$cfg['Server']['user'],
$this->_getBlowfishSecret()
)
);
// Duration = as configured
$GLOBALS['PMA_Config']->setCookie(
'pmaPass-' . $GLOBALS['server'],
$this->blowfishEncrypt(
! empty($cfg['Server']['password'])
? $cfg['Server']['password'] : "\xff(blank)",
$this->_getBlowfishSecret()
),
null,
$GLOBALS['cfg']['LoginCookieStore']
);
// Set server cookies if required (once per session) and, in this case,
// force reload to ensure the client accepts cookies
if (! $GLOBALS['from_cookie']) {
if ($GLOBALS['cfg']['AllowArbitraryServer']) {
if (! empty($GLOBALS['pma_auth_server'])) {
// Duration = one month for servername
$GLOBALS['PMA_Config']->setCookie(
'pmaServer-' . $GLOBALS['server'],
$cfg['Server']['host']
);
} else {
// Delete servername cookie
$GLOBALS['PMA_Config']->removeCookie(
'pmaServer-' . $GLOBALS['server']
);
}
}
// URL where to go:
$redirect_url = $cfg['PmaAbsoluteUri'] . 'index.php';
// any parameters to pass?
$url_params = array();
if (strlen($GLOBALS['db'])) {
$url_params['db'] = $GLOBALS['db'];
}
if (strlen($GLOBALS['table'])) {
$url_params['table'] = $GLOBALS['table'];
}
// any target to pass?
if (! empty($GLOBALS['target'])
&& $GLOBALS['target'] != 'index.php'
) {
$url_params['target'] = $GLOBALS['target'];
}
/**
* Clear user cache.
*/
PMA_Util::clearUserCache();
PMA_Response::getInstance()->disable();
PMA_sendHeaderLocation(
$redirect_url . PMA_URL_getCommon($url_params, '&'),
true
);
if (! defined('TESTSUITE')) {
exit;
} else {
return false;
}
} // end if
return true;
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* prepares error message and switches to auth() which display the error
* and the login form
*
* this function MUST exit/quit the application,
* currently doen by call to auth()
*
* @return void
*/
public function authFails()
{
global $conn_error;
// Deletes password cookie and displays the login form
$GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $GLOBALS['server']);
if (! empty($GLOBALS['login_without_password_is_forbidden'])) {
$conn_error = __(
'Login without a password is forbidden by configuration'
. ' (see AllowNoPassword)'
);
} elseif (! empty($GLOBALS['allowDeny_forbidden'])) {
$conn_error = __('Access denied');
} elseif (! empty($GLOBALS['no_activity'])) {
$conn_error = sprintf(
__('No activity within %s seconds; please log in again.'),
$GLOBALS['cfg']['LoginCookieValidity']
);
} elseif ($GLOBALS['dbi']->getError()) {
$conn_error = '#' . $GLOBALS['errno'] . ' '
. __('Cannot log in to the MySQL server');
} else {
$conn_error = __('Cannot log in to the MySQL server');
}
// needed for PHP-CGI (not need for FastCGI or mod-php)
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
$this->auth();
}
/**
* Returns blowfish secret or generates one if needed.
*
* @return string
*/
private function _getBlowfishSecret()
{
if (empty($GLOBALS['cfg']['blowfish_secret'])) {
if (empty($_SESSION['auto_blowfish_secret'])) {
// this returns 23 characters
$_SESSION['auto_blowfish_secret'] = uniqid('', true);
}
return $_SESSION['auto_blowfish_secret'];
} else {
// apply md5() to work around too long secrets (returns 32 characters)
return md5($GLOBALS['cfg']['blowfish_secret']);
}
}
/**
* Encryption using blowfish algorithm (mcrypt)
* or phpseclib's AES if mcrypt not available
*
* @param string $data original data
* @param string $secret the secret
*
* @return string the encrypted result
*/
public function blowfishEncrypt($data, $secret)
{
global $iv;
if (! function_exists('mcrypt_encrypt')) {
/**
* This library uses mcrypt when available, so
* we could always call it instead of having an
* if/then/else logic, however the include_once
* call is costly
*/
include_once "./libraries/phpseclib/Crypt/AES.php";
$cipher = new Crypt_AES(CRYPT_AES_MODE_ECB);
$cipher->setKey($secret);
return base64_encode($cipher->encrypt($data));
} else {
return base64_encode(
mcrypt_encrypt(
MCRYPT_BLOWFISH,
$secret,
$data,
MCRYPT_MODE_CBC,
$iv
)
);
}
}
/**
* Decryption using blowfish algorithm (mcrypt)
* or phpseclib's AES if mcrypt not available
*
* @param string $encdata encrypted data
* @param string $secret the secret
*
* @return string original data
*/
public function blowfishDecrypt($encdata, $secret)
{
global $iv;
if (! function_exists('mcrypt_encrypt')) {
include_once "./libraries/phpseclib/Crypt/AES.php";
$cipher = new Crypt_AES(CRYPT_AES_MODE_ECB);
$cipher->setKey($secret);
return $cipher->decrypt(base64_decode($encdata));
} else {
$data = base64_decode($encdata);
$decrypted = mcrypt_decrypt(
MCRYPT_BLOWFISH,
$secret,
$data,
MCRYPT_MODE_CBC,
$iv
);
return trim($decrypted);
}
}
/**
* This method is called when any PluginManager to which the observer
* is attached calls PluginManager::notify()
*
* @param SplSubject $subject The PluginManager notifying the observer
* of an update.
*
* @return void
*/
public function update (SplSubject $subject)
{
}
}
@@ -0,0 +1,261 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* HTTP Authentication plugin for phpMyAdmin.
* NOTE: Requires PHP loaded as a Apache module.
*
* @package PhpMyAdmin-Authentication
* @subpackage HTTP
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/* Get the authentication interface */
require_once 'libraries/plugins/AuthenticationPlugin.class.php';
/**
* Handles the HTTP authentication methods
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationHttp extends AuthenticationPlugin
{
/**
* Displays authentication form
*
* @global string the font face to use in case of failure
* @global string the default font size to use in case of failure
* @global string the big font size to use in case of failure
*
* @return boolean always true (no return indeed)
*/
public function auth()
{
/* Perform logout to custom URL */
if (! empty($_REQUEST['old_usr'])
&& ! empty($GLOBALS['cfg']['Server']['LogoutURL'])
) {
PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']);
if (! defined('TESTSUITE')) {
exit;
} else {
return false;
}
}
if (empty($GLOBALS['cfg']['Server']['auth_http_realm'])) {
if (empty($GLOBALS['cfg']['Server']['verbose'])) {
$server_message = $GLOBALS['cfg']['Server']['host'];
} else {
$server_message = $GLOBALS['cfg']['Server']['verbose'];
}
$realm_message = 'phpMyAdmin ' . $server_message;
} else {
$realm_message = $GLOBALS['cfg']['Server']['auth_http_realm'];
}
// remove non US-ASCII to respect RFC2616
$realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message);
header('WWW-Authenticate: Basic realm="' . $realm_message . '"');
header('HTTP/1.0 401 Unauthorized');
if (php_sapi_name() !== 'cgi-fcgi') {
header('status: 401 Unauthorized');
}
/* HTML header */
$response = PMA_Response::getInstance();
$response->getFooter()->setMinimal();
$header = $response->getHeader();
$header->setTitle(__('Access denied'));
$header->disableMenu();
$header->setBodyId('loginform');
$response->addHTML('<h1>');
$response->addHTML(sprintf(__('Welcome to %s'), ' phpMyAdmin'));
$response->addHTML('</h1>');
$response->addHTML('<h3>');
$response->addHTML(
PMA_Message::error(
__('Wrong username/password. Access denied.')
)
);
$response->addHTML('</h3>');
if (file_exists(CUSTOM_FOOTER_FILE)) {
include CUSTOM_FOOTER_FILE;
}
if (! defined('TESTSUITE')) {
exit;
} else {
return false;
}
}
/**
* Gets advanced authentication settings
*
* @global string $PHP_AUTH_USER the username if register_globals is on
* @global string $PHP_AUTH_PW the password if register_globals is on
* @global array the array of server variables if
* register_globals is off
* @global array the array of environment variables if
* register_globals is off
* @global string the username for the ? server
* @global string the password for the ? server
* @global string the username for the WebSite Professional
* server
* @global string the password for the WebSite Professional
* server
* @global string the username of the user who logs out
*
* @return boolean whether we get authentication settings or not
*/
public function authCheck()
{
global $PHP_AUTH_USER, $PHP_AUTH_PW;
// Grabs the $PHP_AUTH_USER variable whatever are the values of the
// 'register_globals' and the 'variables_order' directives
if (empty($PHP_AUTH_USER)) {
if (PMA_getenv('PHP_AUTH_USER')) {
$PHP_AUTH_USER = PMA_getenv('PHP_AUTH_USER');
} elseif (PMA_getenv('REMOTE_USER')) {
// CGI, might be encoded, see below
$PHP_AUTH_USER = PMA_getenv('REMOTE_USER');
} elseif (PMA_getenv('REDIRECT_REMOTE_USER')) {
// CGI, might be encoded, see below
$PHP_AUTH_USER = PMA_getenv('REDIRECT_REMOTE_USER');
} elseif (PMA_getenv('AUTH_USER')) {
// WebSite Professional
$PHP_AUTH_USER = PMA_getenv('AUTH_USER');
} elseif (PMA_getenv('HTTP_AUTHORIZATION')
&& false === strpos(PMA_getenv('HTTP_AUTHORIZATION'), '<')
) {
// IIS, might be encoded, see below; also prevent XSS
$PHP_AUTH_USER = PMA_getenv('HTTP_AUTHORIZATION');
} elseif (PMA_getenv('Authorization')) {
// FastCGI, might be encoded, see below
$PHP_AUTH_USER = PMA_getenv('Authorization');
}
}
// Grabs the $PHP_AUTH_PW variable whatever are the values of the
// 'register_globals' and the 'variables_order' directives
if (empty($PHP_AUTH_PW)) {
if (PMA_getenv('PHP_AUTH_PW')) {
$PHP_AUTH_PW = PMA_getenv('PHP_AUTH_PW');
} elseif (PMA_getenv('REMOTE_PASSWORD')) {
// Apache/CGI
$PHP_AUTH_PW = PMA_getenv('REMOTE_PASSWORD');
} elseif (PMA_getenv('AUTH_PASSWORD')) {
// WebSite Professional
$PHP_AUTH_PW = PMA_getenv('AUTH_PASSWORD');
}
}
// Decode possibly encoded information (used by IIS/CGI/FastCGI)
// (do not use explode() because a user might have a colon in his password
if (strcmp(substr($PHP_AUTH_USER, 0, 6), 'Basic ') == 0) {
$usr_pass = base64_decode(substr($PHP_AUTH_USER, 6));
if (! empty($usr_pass)) {
$colon = strpos($usr_pass, ':');
if ($colon) {
$PHP_AUTH_USER = substr($usr_pass, 0, $colon);
$PHP_AUTH_PW = substr($usr_pass, $colon + 1);
}
unset($colon);
}
unset($usr_pass);
}
// User logged out -> ensure the new username is not the same
$old_usr = isset($_REQUEST['old_usr']) ? $_REQUEST['old_usr'] : '';
if (! empty($old_usr)
&& (isset($PHP_AUTH_USER) && $old_usr == $PHP_AUTH_USER)
) {
$PHP_AUTH_USER = '';
// -> delete user's choices that were stored in session
if (! defined('TESTSUITE')) {
session_destroy();
}
}
// Returns whether we get authentication settings or not
if (empty($PHP_AUTH_USER)) {
return false;
} else {
return true;
}
}
/**
* Set the user and password after last checkings if required
*
* @global array $cfg the valid servers settings
* @global integer $server the id of the current server
* @global array the current server settings
* @global string $PHP_AUTH_USER the current username
* @global string $PHP_AUTH_PW the current password
*
* @return boolean always true
*/
public function authSetUser()
{
global $cfg, $server;
global $PHP_AUTH_USER, $PHP_AUTH_PW;
// Ensures valid authentication mode, 'only_db', bookmark database and
// table names and relation table name are used
if ($cfg['Server']['user'] != $PHP_AUTH_USER) {
$servers_cnt = count($cfg['Servers']);
for ($i = 1; $i <= $servers_cnt; $i++) {
if (isset($cfg['Servers'][$i])
&& ($cfg['Servers'][$i]['host'] == $cfg['Server']['host']
&& $cfg['Servers'][$i]['user'] == $PHP_AUTH_USER)
) {
$server = $i;
$cfg['Server'] = $cfg['Servers'][$i];
break;
}
} // end for
} // end if
$cfg['Server']['user'] = $PHP_AUTH_USER;
$cfg['Server']['password'] = $PHP_AUTH_PW;
// Avoid showing the password in phpinfo()'s output
unset($GLOBALS['PHP_AUTH_PW']);
unset($_SERVER['PHP_AUTH_PW']);
return true;
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* @return boolean always true (no return indeed)
*/
public function authFails()
{
$error = $GLOBALS['dbi']->getError();
if ($error && $GLOBALS['errno'] != 1045) {
PMA_fatalError($error);
} else {
$this->auth();
return true;
}
}
/**
* This method is called when any PluginManager to which the observer
* is attached calls PluginManager::notify()
*
* @param SplSubject $subject The PluginManager notifying the observer
* of an update.
*
* @return void
*/
public function update (SplSubject $subject)
{
}
}
@@ -0,0 +1,299 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* SignOn Authentication plugin for phpMyAdmin
*
* @package PhpMyAdmin-Authentication
* @subpackage SignOn
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/* Get the authentication interface */
require_once 'libraries/plugins/AuthenticationPlugin.class.php';
/**
* Handles the SignOn authentication method
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationSignon extends AuthenticationPlugin
{
/**
* Displays authentication form
*
* @global string the font face to use in case of failure
* @global string the default font size to use in case of failure
* @global string the big font size to use in case of failure
*
* @return boolean always true (no return indeed)
*/
public function auth()
{
unset($_SESSION['LAST_SIGNON_URL']);
if (empty($GLOBALS['cfg']['Server']['SignonURL'])) {
PMA_fatalError('You must set SignonURL!');
} elseif (! empty($_REQUEST['old_usr'])
&& ! empty($GLOBALS['cfg']['Server']['LogoutURL'])
) {
/* Perform logout to custom URL */
PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']);
} else {
PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['SignonURL']);
}
if (! defined('TESTSUITE')) {
exit();
} else {
return false;
}
}
/**
* Gets advanced authentication settings
*
* @global string $PHP_AUTH_USER the username if register_globals is on
* @global string $PHP_AUTH_PW the password if register_globals is on
* @global array the array of server variables if
* register_globals is off
* @global array the array of environment variables if
* register_globals is off
* @global string the username for the ? server
* @global string the password for the ? server
* @global string the username for the WebSite Professional server
* @global string the password for the WebSite Professional server
* @global string the username of the user who logs out
*
* @return boolean whether we get authentication settings or not
*/
public function authCheck()
{
global $PHP_AUTH_USER, $PHP_AUTH_PW;
/* Check if we're using same sigon server */
$signon_url = $GLOBALS['cfg']['Server']['SignonURL'];
if (isset($_SESSION['LAST_SIGNON_URL'])
&& $_SESSION['LAST_SIGNON_URL'] != $signon_url
) {
return false;
}
/* Script name */
$script_name = $GLOBALS['cfg']['Server']['SignonScript'];
/* Session name */
$session_name = $GLOBALS['cfg']['Server']['SignonSession'];
/* Login URL */
$signon_url = $GLOBALS['cfg']['Server']['SignonURL'];
/* Current host */
$single_signon_host = $GLOBALS['cfg']['Server']['host'];
/* Current port */
$single_signon_port = $GLOBALS['cfg']['Server']['port'];
/* No configuration updates */
$single_signon_cfgupdate = array();
/* Are we requested to do logout? */
$do_logout = !empty($_REQUEST['old_usr']);
/* Handle script based auth */
if (!empty($script_name)) {
if (! file_exists($script_name)) {
PMA_fatalError(
__('Can not find signon authentication script:')
. ' '. $script_name
);
}
include $script_name;
list ($PHP_AUTH_USER, $PHP_AUTH_PW)
= get_login_credentials($GLOBALS['cfg']['Server']['user']);
} elseif (isset($_COOKIE[$session_name])) { /* Does session exist? */
/* End current session */
$old_session = session_name();
$old_id = session_id();
if (! defined('TESTSUITE')) {
session_write_close();
}
/* Load single signon session */
session_name($session_name);
session_id($_COOKIE[$session_name]);
if (! defined('TESTSUITE')) {
session_start();
}
/* Clear error message */
unset($_SESSION['PMA_single_signon_error_message']);
/* Grab credentials if they exist */
if (isset($_SESSION['PMA_single_signon_user'])) {
if ($do_logout) {
$PHP_AUTH_USER = '';
} else {
$PHP_AUTH_USER = $_SESSION['PMA_single_signon_user'];
}
}
if (isset($_SESSION['PMA_single_signon_password'])) {
if ($do_logout) {
$PHP_AUTH_PW = '';
} else {
$PHP_AUTH_PW = $_SESSION['PMA_single_signon_password'];
}
}
if (isset($_SESSION['PMA_single_signon_host'])) {
$single_signon_host = $_SESSION['PMA_single_signon_host'];
}
if (isset($_SESSION['PMA_single_signon_port'])) {
$single_signon_port = $_SESSION['PMA_single_signon_port'];
}
if (isset($_SESSION['PMA_single_signon_cfgupdate'])) {
$single_signon_cfgupdate = $_SESSION['PMA_single_signon_cfgupdate'];
}
/* Also get token as it is needed to access subpages */
if (isset($_SESSION['PMA_single_signon_token'])) {
/* No need to care about token on logout */
$pma_token = $_SESSION['PMA_single_signon_token'];
}
/* End single signon session */
if (! defined('TESTSUITE')) {
session_write_close();
}
/* Restart phpMyAdmin session */
session_name($old_session);
if (!empty($old_id)) {
session_id($old_id);
}
if (! defined('TESTSUITE')) {
session_start();
}
/* Set the single signon host */
$GLOBALS['cfg']['Server']['host'] = $single_signon_host;
/* Set the single signon port */
$GLOBALS['cfg']['Server']['port'] = $single_signon_port;
/* Configuration update */
$GLOBALS['cfg']['Server'] = array_merge(
$GLOBALS['cfg']['Server'],
$single_signon_cfgupdate
);
/* Restore our token */
if (!empty($pma_token)) {
$_SESSION[' PMA_token '] = $pma_token;
}
/**
* Clear user cache.
*/
PMA_Util::clearUserCache();
}
// Returns whether we get authentication settings or not
if (empty($PHP_AUTH_USER)) {
unset($_SESSION['LAST_SIGNON_URL']);
return false;
} else {
$_SESSION['LAST_SIGNON_URL'] = $GLOBALS['cfg']['Server']['SignonURL'];
return true;
}
}
/**
* Set the user and password after last checkings if required
*
* @global array $cfg the valid servers settings
* @global integer the id of the current server
* @global array the current server settings
* @global string $PHP_AUTH_USER the current username
* @global string $PHP_AUTH_PW the current password
*
* @return boolean always true
*/
public function authSetUser()
{
global $cfg;
global $PHP_AUTH_USER, $PHP_AUTH_PW;
$cfg['Server']['user'] = $PHP_AUTH_USER;
$cfg['Server']['password'] = $PHP_AUTH_PW;
return true;
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* @return boolean always true (no return indeed)
*/
public function authFails()
{
/* Session name */
$session_name = $GLOBALS['cfg']['Server']['SignonSession'];
/* Does session exist? */
if (isset($_COOKIE[$session_name])) {
/* End current session */
if (! defined('TESTSUITE')) {
session_write_close();
}
/* Load single signon session */
session_name($session_name);
session_id($_COOKIE[$session_name]);
if (! defined('TESTSUITE')) {
session_start();
}
/* Set error message */
if (! empty($GLOBALS['login_without_password_is_forbidden'])) {
$_SESSION['PMA_single_signon_error_message'] = __(
'Login without a password is forbidden by configuration '
. '(see AllowNoPassword)'
);
} elseif (! empty($GLOBALS['allowDeny_forbidden'])) {
$_SESSION['PMA_single_signon_error_message'] = __('Access denied');
} elseif (! empty($GLOBALS['no_activity'])) {
$_SESSION['PMA_single_signon_error_message'] = sprintf(
__('No activity within %s seconds; please log in again.'),
$GLOBALS['cfg']['LoginCookieValidity']
);
} elseif ($GLOBALS['dbi']->getError()) {
$_SESSION['PMA_single_signon_error_message'] = PMA_sanitize(
$GLOBALS['dbi']->getError()
);
} else {
$_SESSION['PMA_single_signon_error_message'] = __(
'Cannot log in to the MySQL server'
);
}
}
$this->auth();
}
/**
* This method is called when any PluginManager to which the observer
* is attached calls PluginManager::notify()
*
* @param SplSubject $subject The PluginManager notifying the observer
* of an update.
*
* @return void
*/
public function update (SplSubject $subject)
{
}
}
@@ -0,0 +1,277 @@
<?php
/*
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* http://recaptcha.net/plugins/php/
* - Get a reCAPTCHA API Key
* https://www.google.com/recaptcha/admin/create
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
* AUTHORS:
* Mike Crawford
* Ben Maurer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The reCAPTCHA server URL's
*/
define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
/**
* Encodes the given data into a query string format
* @param $data - array of string elements to be encoded
* @return string - encoded request
*/
function _recaptcha_qsencode ($data) {
$req = "";
foreach ( $data as $key => $value )
$req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
// Cut the last '&'
$req=substr($req,0,strlen($req)-1);
return $req;
}
/**
* Submits an HTTP POST to a reCAPTCHA server
* @param string $host
* @param string $path
* @param array $data
* @param int port
* @return array response
*/
function _recaptcha_http_post($host, $path, $data, $port = 80) {
$req = _recaptcha_qsencode ($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
$response = '';
if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
die ('Could not open socket');
}
fwrite($fs, $http_request);
while ( !feof($fs) )
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
/**
* Gets the challenge HTML (javascript and non-javascript version).
* This is called from the browser, and the resulting reCAPTCHA HTML widget
* is embedded within the HTML form it was called from.
* @param string $pubkey A public key for reCAPTCHA
* @param string $error The error given by reCAPTCHA (optional, default is null)
* @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
* @return string - The HTML to be embedded in the user's form.
*/
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
{
if ($pubkey == null || $pubkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($use_ssl) {
$server = RECAPTCHA_API_SECURE_SERVER;
} else {
$server = RECAPTCHA_API_SERVER;
}
$errorpart = "";
if ($error) {
$errorpart = "&amp;error=" . $error;
}
return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
<noscript>
<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>';
}
/**
* A ReCaptchaResponse is returned from recaptcha_check_answer()
*/
class ReCaptchaResponse {
var $is_valid;
var $error;
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
* @param string $privkey
* @param string $remoteip
* @param string $challenge
* @param string $response
* @param array $extra_params an array of extra variables to post to the server
* @return ReCaptchaResponse
*/
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
{
if ($privkey == null || $privkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($remoteip == null || $remoteip == '') {
die ("For security reasons, you must pass the remote ip to reCAPTCHA");
}
//discard spam submissions
if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
$recaptcha_response = new ReCaptchaResponse();
$recaptcha_response->is_valid = false;
$recaptcha_response->error = 'incorrect-captcha-sol';
return $recaptcha_response;
}
$response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
array (
'privatekey' => $privkey,
'remoteip' => $remoteip,
'challenge' => $challenge,
'response' => $response
) + $extra_params
);
$answers = explode ("\n", $response [1]);
$recaptcha_response = new ReCaptchaResponse();
if (trim ($answers [0]) == 'true') {
$recaptcha_response->is_valid = true;
}
else {
$recaptcha_response->is_valid = false;
$recaptcha_response->error = $answers [1];
}
return $recaptcha_response;
}
/**
* gets a URL where the user can sign up for reCAPTCHA. If your application
* has a configuration page where you enter a key, you should provide a link
* using this function.
* @param string $domain The domain where the page is hosted
* @param string $appname The name of your application
*/
function recaptcha_get_signup_url ($domain = null, $appname = null) {
return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
}
function _recaptcha_aes_pad($val) {
$block_size = 16;
$numpad = $block_size - (strlen ($val) % $block_size);
return str_pad($val, strlen ($val) + $numpad, chr($numpad));
}
/* Mailhide related code */
function _recaptcha_aes_encrypt($val,$ky) {
if (! function_exists ("mcrypt_encrypt")) {
die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
}
$mode=MCRYPT_MODE_CBC;
$enc=MCRYPT_RIJNDAEL_128;
$val=_recaptcha_aes_pad($val);
return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}
function _recaptcha_mailhide_urlbase64 ($x) {
return strtr(base64_encode ($x), '+/', '-_');
}
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
"you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
}
$ky = pack('H*', $privkey);
$cryptmail = _recaptcha_aes_encrypt ($email, $ky);
return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
}
/**
* gets the parts of the email to expose to the user.
* eg, given johndoe@example,com return ["john", "example.com"].
* the email is then displayed as john...@example.com
*/
function _recaptcha_mailhide_email_parts ($email) {
$arr = preg_split("/@/", $email );
if (strlen ($arr[0]) <= 4) {
$arr[0] = substr ($arr[0], 0, 1);
} else if (strlen ($arr[0]) <= 6) {
$arr[0] = substr ($arr[0], 0, 3);
} else {
$arr[0] = substr ($arr[0], 0, 4);
}
return $arr;
}
/**
* Gets html to display an email address given a public an private key.
* to get a key, go to:
*
* http://www.google.com/recaptcha/mailhide/apikey
*/
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
$emailparts = _recaptcha_mailhide_email_parts ($email);
$url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
"' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
}
?>
@@ -0,0 +1,172 @@
<?php
/**
* @package Swekey
*/
?>
<script>
var g_SwekeyPlugin = null;
// -------------------------------------------------------------------
// Create the swekey plugin if it does not exists
function Swekey_Plugin()
{
try
{
if (g_SwekeyPlugin != null)
return g_SwekeyPlugin;
if (window.ActiveXObject)
{
g_SwekeyPlugin = document.getElementById("swekey_activex");
if (g_SwekeyPlugin == null)
{
// we must create the activex that way instead of new ActiveXObject("FbAuthAx.FbAuthCtl");
// ortherwise SetClientSite is not called and we can not get the url
var div = document.createElement('div');
div.innerHTML='<object id="swekey_activex" style="display:none" CLASSID="CLSID:8E02E3F9-57AA-4EE1-AA68-A42DD7B0FADE"></object>';
// Never append to the body because it may still loading and it breaks IE
document.body.insertBefore(div, document.body.firstChild);
g_SwekeyPlugin = document.getElementById("swekey_activex");
}
return g_SwekeyPlugin;
}
g_SwekeyPlugin = document.getElementById("swekey_plugin");
if (g_SwekeyPlugin != null)
return g_SwekeyPlugin;
for (i = 0; i < navigator.plugins.length; i ++)
{
try
{
if (navigator.plugins[i] == null)
{
navigator.plugins.refresh();
}
else if (navigator.plugins[i][0] != null && navigator.plugins[i][0].type == "application/fbauth-plugin")
{
var x = document.createElement('embed');
x.setAttribute('type', 'application/fbauth-plugin');
x.setAttribute('id', 'swekey_plugin');
x.setAttribute('width', '0');
x.setAttribute('height', '0');
x.style.dislay='none';
//document.body.appendChild(x);
document.body.insertBefore(x, document.body.firstChild);
g_SwekeyPlugin = document.getElementById("swekey_plugin");
return g_SwekeyPlugin;
}
}
catch (e)
{
navigator.plugins.refresh();
//alert ('Failed to create plugin: ' + e);
}
}
}
catch (e)
{
//alert("Swekey_Plugin " + e);
g_SwekeyPlugin = null;
}
return null;
}
// -------------------------------------------------------------------
// Returns true if the swekey plugin is installed
function Swekey_Installed()
{
return (Swekey_Plugin() != null);
}
// -------------------------------------------------------------------
// List the id of the Swekey connected to the PC
// Returns a string containing comma separated Swekey Ids
// A Swekey is a 32 char hexadecimal value.
function Swekey_ListKeyIds()
{
try
{
return Swekey_Plugin().list();
}
catch (e)
{
// alert("Swekey_ListKeyIds " + e);
}
return "";
}
// -------------------------------------------------------------------
// Ask the Connected Swekey to generate an OTP
// id: The id of the connected Swekey (returne by Swekey_ListKeyIds())
// rt: A random token
// return: The calculated OTP encoded in a 64 chars hexadecimal value.
function Swekey_GetOtp(id, rt)
{
try
{
return Swekey_Plugin().getotp(id, rt);
}
catch (e)
{
// alert("Swekey_GetOtp " + e);
}
return "";
}
// -------------------------------------------------------------------
// Ask the Connected Swekey to generate a OTP linked to the current https host
// id: The id of the connected Swekey (returne by Swekey_ListKeyIds())
// rt: A random token
// return: The calculated OTP encoded in a 64 chars hexadecimal value.
// or "" if the current url does not start with https
function Swekey_GetLinkedOtp(id, rt)
{
try
{
return Swekey_Plugin().getlinkedotp(id, rt);
}
catch (e)
{
// alert("Swekey_GetSOtp " + e);
}
return "";
}
// -------------------------------------------------------------------
// Calls Swekey_GetOtp or Swekey_GetLinkedOtp depending if we are in
// an https page or not.
// id: The id of the connected Swekey (returne by Swekey_ListKeyIds())
// rt: A random token
// return: The calculated OTP encoded in a 64 chars hexadecimal value.
function Swekey_GetSmartOtp(id, rt)
{
var res = Swekey_GetLinkedOtp(id, rt);
if (res == "")
res = Swekey_GetOtp(id, rt);
return res;
}
// -------------------------------------------------------------------
// Set a unplug handler (url) to the specified connected feebee
// id: The id of the connected Swekey (returne by Swekey_ListKeyIds())
// key: The key that index that url, (aplhanumeric values only)
// url: The url that will be launched ("" deletes the url)
function Swekey_SetUnplugUrl(id, key, url)
{
try
{
return Swekey_Plugin().setunplugurl(id, key, url);
}
catch (e)
{
// alert("Swekey_SetUnplugUrl " + e);
}
}
</script>
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIJAMjw7QcLWCd6MA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5j
LjESMBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2Jl
LmNvbTAeFw0wODA5MDQxNDE2MTNaFw0zNzEyMjExNDE2MTNaMGsxCzAJBgNVBAYT
AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES
MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOBhOljxVzQfK4gted2I
d3BemcjW4abAUOzn3KYWXpPO5xIfVeXNDGkDbyH+X+7fo94sX25/ewuKNFDSOcvo
tXHq7uQenTHB35r+a+LY81KceUHgW90a3XsqPAkwAjyYcgo3zmM2DtLvw+5Yod8T
wAHk9m3qavnQ1uk99jBTwL7RZ9jIZHh9pFCL93uJc2obtd8O96Iycbn2q0w/AWbb
+eUVWIHzvLtfPvROeL3lJzr/Uz5LjKapxJ3qyqASflfHpnj9pU8l6g2TQ6Hg5KT5
tLFkRe7uGhOfRtOQ/+NjaWrEuNCFnpyN4Q5Fv+5qA1Ip1IpH0200sWbAf/k2u0Qp
Sx0CAwEAAaOB0DCBzTAdBgNVHQ4EFgQUczJrQ7hCvtsnzcqiDIZ/GSn/CiwwgZ0G
A1UdIwSBlTCBkoAUczJrQ7hCvtsnzcqiDIZ/GSn/Ciyhb6RtMGsxCzAJBgNVBAYT
AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES
MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv
bYIJAMjw7QcLWCd6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGxk
8xzIljeBDQWWVRr0NEALVSv3i09V4jAKkyEOfmZ8lKMKJi0atwbtjrXTzLnNYj+Q
pyUbyY/8ItWvV7pnVxMiF9qcer7e9X4vw358GZuMVE/da1nWxz+CwzTm5oO30RzA
antM9bISFFr9lJq69bDWOnCUi1IG8DSL3TxtlABso7S4vqiZ+sB33l6k1K4a/Njb
QkU9UejKhKkVVZTsOrumfnOJ4MCmPfX8Y/AY2o670y5HnzpxerIYziCVzApPVrW7
sKH0tuVGturMfQOKgstYe4/m9glBTeTLMkjD+6MJC2ONBD7GAiOO95gNl5M1fzJQ
FEe5CJ7DCYl0GdmLXXw=
-----END CERTIFICATE-----
@@ -0,0 +1,302 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* @package Swekey
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/**
* Checks Swekey authentication.
*/
function Swekey_Auth_check()
{
global $cfg;
$confFile = $cfg['Server']['auth_swekey_config'];
if (! isset($_SESSION['SWEKEY'])) {
$_SESSION['SWEKEY'] = array();
}
$_SESSION['SWEKEY']['ENABLED'] = (! empty($confFile) && file_exists($confFile));
// Load the swekey.conf file the first time
if ($_SESSION['SWEKEY']['ENABLED']
&& empty($_SESSION['SWEKEY']['CONF_LOADED'])
) {
$_SESSION['SWEKEY']['CONF_LOADED'] = true;
$_SESSION['SWEKEY']['VALID_SWEKEYS'] = array();
$valid_swekeys = explode("\n", @file_get_contents($confFile));
foreach ($valid_swekeys as $line) {
if (preg_match("/^[0-9A-F]{32}:.+$/", $line) != false) {
$items = explode(":", $line);
if (count($items) == 2) {
$_SESSION['SWEKEY']['VALID_SWEKEYS'][$items[0]] = trim($items[1]);
}
} elseif (preg_match("/^[A-Z_]+=.*$/", $line) != false) {
$items = explode("=", $line);
$_SESSION['SWEKEY']['CONF_'.trim($items[0])] = trim($items[1]);
}
}
// Set default values for settings
if (! isset($_SESSION['SWEKEY']['CONF_SERVER_CHECK'])) {
$_SESSION['SWEKEY']['CONF_SERVER_CHECK'] = "";
}
if (! isset($_SESSION['SWEKEY']['CONF_SERVER_RNDTOKEN'])) {
$_SESSION['SWEKEY']['CONF_SERVER_RNDTOKEN'] = "";
}
if (! isset($_SESSION['SWEKEY']['CONF_SERVER_STATUS'])) {
$_SESSION['SWEKEY']['CONF_SERVER_STATUS'] = "";
}
if (! isset($_SESSION['SWEKEY']['CONF_CA_FILE'])) {
$_SESSION['SWEKEY']['CONF_CA_FILE'] = "";
}
if (! isset($_SESSION['SWEKEY']['CONF_ENABLE_TOKEN_CACHE'])) {
$_SESSION['SWEKEY']['CONF_ENABLE_TOKEN_CACHE'] = true;
}
if (! isset($_SESSION['SWEKEY']['CONF_DEBUG'])) {
$_SESSION['SWEKEY']['CONF_DEBUG'] = false;
}
}
// check if a web key has been authenticated
if ($_SESSION['SWEKEY']['ENABLED']) {
if (empty($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'])) {
return false;
}
}
return true;
}
/**
* Handle Swekey authentication error.
*/
function Swekey_Auth_error()
{
if (! isset($_SESSION['SWEKEY'])) {
return null;
}
if (! $_SESSION['SWEKEY']['ENABLED']) {
return null;
}
include_once './libraries/plugins/auth/swekey/authentication.inc.php';
?>
<script>
function Swekey_GetValidKey()
{
var valids = "<?php
foreach ($_SESSION['SWEKEY']['VALID_SWEKEYS'] as $key => $value) {
echo $key.',';
}
?>";
var connected_keys = Swekey_ListKeyIds().split(",");
for (i in connected_keys) {
if (connected_keys[i] != null && connected_keys[i].length == 32) {
if (valids.indexOf(connected_keys[i]) >= 0) {
return connected_keys[i];
}
}
}
if (connected_keys.length > 0) {
if (connected_keys[0].length == 32) {
return "unknown_key_" + connected_keys[0];
}
}
return "none";
}
var key = Swekey_GetValidKey();
function timedCheck()
{
if (key != Swekey_GetValidKey()) {
window.location.search = "?swekey_reset";
} else {
setTimeout("timedCheck()",1000);
}
}
setTimeout("timedCheck()",1000);
</script>
<?php
if (! empty($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'])) {
return null;
}
if (count($_SESSION['SWEKEY']['VALID_SWEKEYS']) == 0) {
return sprintf(
__('File %s does not contain any key id'),
$GLOBALS['cfg']['Server']['auth_swekey_config']
);
}
include_once "libraries/plugins/auth/swekey/swekey.php";
Swekey_SetCheckServer($_SESSION['SWEKEY']['CONF_SERVER_CHECK']);
Swekey_SetRndTokenServer($_SESSION['SWEKEY']['CONF_SERVER_RNDTOKEN']);
Swekey_SetStatusServer($_SESSION['SWEKEY']['CONF_SERVER_STATUS']);
Swekey_EnableTokenCache($_SESSION['SWEKEY']['CONF_ENABLE_TOKEN_CACHE']);
$caFile = $_SESSION['SWEKEY']['CONF_CA_FILE'];
if (empty($caFile)) {
$caFile = __FILE__;
$pos = strrpos($caFile, '/');
if ($pos === false) {
$pos = strrpos($caFile, '\\'); // windows
}
$caFile = substr($caFile, 0, $pos + 1).'musbe-ca.crt';
// echo "\n<!-- $caFile -->\n";
// if (file_exists($caFile))
// echo "<!-- exists -->\n";
}
if (file_exists($caFile)) {
Swekey_SetCAFile($caFile);
} elseif (! empty($caFile)
&& (substr($_SESSION['SWEKEY']['CONF_SERVER_CHECK'], 0, 8) == "https://")) {
return "Internal Error: CA File $caFile not found";
}
$result = null;
$swekey_id = $_GET['swekey_id'];
$swekey_otp = $_GET['swekey_otp'];
if (isset($swekey_id)) {
unset($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY']);
if (! isset($_SESSION['SWEKEY']['RND_TOKEN'])) {
unset($swekey_id);
} else {
if (strlen($swekey_id) == 32) {
$res = Swekey_CheckOtp($swekey_id, $_SESSION['SWEKEY']['RND_TOKEN'], $swekey_otp);
unset($_SESSION['SWEKEY']['RND_TOKEN']);
if (! $res) {
$result = __('Hardware authentication failed!') . ' (' . Swekey_GetLastError() . ')';
} else {
$_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'] = $swekey_id;
$_SESSION['SWEKEY']['FORCE_USER'] = $_SESSION['SWEKEY']['VALID_SWEKEYS'][$swekey_id];
return null;
}
} else {
$result = __('No valid authentication key plugged');
if ($_SESSION['SWEKEY']['CONF_DEBUG']) {
$result .= "<br/>" . htmlspecialchars($swekey_id);
}
unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file
}
}
} else {
unset($_SESSION['SWEKEY']);
}
$_SESSION['SWEKEY']['RND_TOKEN'] = Swekey_GetFastRndToken();
if (strlen($_SESSION['SWEKEY']['RND_TOKEN']) != 64) {
$result = __('Hardware authentication failed!') . ' (' . Swekey_GetLastError() . ')';
unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file
}
if (! isset($swekey_id)) {
?>
<script>
if (key.length != 32) {
window.location.search="?swekey_id=" + key + "&token=<?php echo $_SESSION[' PMA_token ']; ?>";
} else {
var url = "" + window.location;
if (url.indexOf("?") > 0) {
url = url.substr(0, url.indexOf("?"));
}
Swekey_SetUnplugUrl(key, "pma_login", url + "?session_to_unset=<?php echo session_id();?>&token=<?php echo $_SESSION[' PMA_token ']; ?>");
var otp = Swekey_GetOtp(key, <?php echo '"'.$_SESSION['SWEKEY']['RND_TOKEN'].'"';?>);
window.location.search="?swekey_id=" + key + "&swekey_otp=" + otp + "&token=<?php echo $_SESSION[' PMA_token ']; ?>";
}
</script>
<?php
return __('Authenticating…');
}
return $result;
}
/**
* Perform login using Swekey.
*/
function Swekey_login($input_name, $input_go)
{
$swekeyErr = Swekey_Auth_error();
if ($swekeyErr != null) {
PMA_Message::error($swekeyErr)->display();
if ($GLOBALS['error_handler']->hasDisplayErrors()) {
echo '<div>';
$GLOBALS['error_handler']->dispErrors();
echo '</div>';
}
}
if (isset($_SESSION['SWEKEY']) && $_SESSION['SWEKEY']['ENABLED']) {
echo '<script type="text/javascript">';
if (empty($_SESSION['SWEKEY']['FORCE_USER'])) {
echo 'var user = null;';
} else {
echo 'var user = "'.$_SESSION['SWEKEY']['FORCE_USER'].'";';
}
?>
function open_swekey_site()
{
window.open("<?php echo PMA_linkURL('http://phpmyadmin.net/auth_key'); ?>");
}
var input_username = document.getElementById("<?php echo $input_name; ?>");
var input_go = document.getElementById("<?php echo $input_go; ?>");
var swekey_status = document.createElement('img');
swekey_status.setAttribute('onclick', 'open_swekey_site()');
swekey_status.setAttribute('style', 'width:8px; height:16px; border:0px; vspace:0px; hspace:0px; frameborder:no');
if (user == null) {
swekey_status.setAttribute('src', 'http://artwork.swekey.com/unplugged-8x16.png');
//swekey_status.setAttribute('title', 'No swekey plugged');
input_go.disabled = true;
} else {
swekey_status.setAttribute('src', 'http://artwork.swekey.com/plugged-8x16.png');
//swekey_status.setAttribute('title', 'swekey plugged');
input_username.value = user;
}
input_username.readOnly = true;
if (input_username.nextSibling == null) {
input_username.parentNode.appendChild(swekey_status);
} else {
input_username.parentNode.insertBefore(swekey_status, input_username.nextSibling);
}
<?php
echo '</script>';
}
}
if (!empty($_GET['session_to_unset'])) {
session_write_close();
session_id($_GET['session_to_unset']);
session_start();
$_SESSION = array();
session_write_close();
session_destroy();
exit;
}
if (isset($_GET['swekey_reset'])) {
unset($_SESSION['SWEKEY']);
}
?>
@@ -0,0 +1,522 @@
<?php
/**
* Library that provides common functions that are used to help integrating Swekey Authentication in a PHP web site
* Version 1.0
*
* History:
* 1.2 Use curl (widely installed) to query the server
* Fixed a possible tempfile race attack
* Random token cache can now be disabled
* 1.1 Added Swekey_HttpGet function that support faulty servers
* Support for custom servers
* 1.0 First release
*
* @package Swekey
*/
/**
* Errors codes
*/
define("SWEKEY_ERR_INVALID_DEV_STATUS", 901); // The satus of the device is not SWEKEY_STATUS_OK
define("SWEKEY_ERR_INTERNAL", 902); // Should never occurd
define("SWEKEY_ERR_OUTDATED_RND_TOKEN", 910); // You random token is too old
define("SWEKEY_ERR_INVALID_OTP", 911); // The otp was not correct
/**
* Those errors are considered as an attack and your site will be blacklisted during one minute
* if you receive one of those errors
*/
define("SWEKEY_ERR_BADLY_ENCODED_REQUEST", 920);
define("SWEKEY_ERR_INVALID_RND_TOKEN", 921);
define("SWEKEY_ERR_DEV_NOT_FOUND", 922);
/**
* Default values for configuration.
*/
define('SWEKEY_DEFAULT_CHECK_SERVER', 'https://auth-check.musbe.net');
define('SWEKEY_DEFAULT_RND_SERVER', 'https://auth-rnd-gen.musbe.net');
define('SWEKEY_DEFAULT_STATUS_SERVER', 'https://auth-status.musbe.net');
/**
* The last error of an operation is alway put in this global var
*/
global $gSwekeyLastError;
$gSwekeyLastError = 0;
global $gSwekeyLastResult;
$gSwekeyLastResult = "<not set>";
/**
* Servers addresses
* Use the Swekey_SetXxxServer($server) functions to set them
*/
global $gSwekeyCheckServer;
if (! isset($gSwekeyCheckServer)) {
$gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;
}
global $gSwekeyRndTokenServer;
if (! isset($gSwekeyRndTokenServer)) {
$gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;
}
global $gSwekeyStatusServer;
if (! isset($gSwekeyStatusServer)) {
$gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;
}
global $gSwekeyCA;
global $gSwekeyTokenCacheEnabled;
if (! isset($gSwekeyTokenCacheEnabled)) {
$gSwekeyTokenCacheEnabled = true;
}
/**
* Change the address of the Check server.
* If $server is empty the default value 'http://auth-check.musbe.net' will be used
*
* @param server The protocol and hostname to use
*
* @access public
*/
function Swekey_SetCheckServer($server)
{
global $gSwekeyCheckServer;
if (empty($server)) {
$gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;
} else {
$gSwekeyCheckServer = $server;
}
}
/**
* Change the address of the Random Token Generator server.
* If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used
*
* @param server The protocol and hostname to use
*
* @access public
*/
function Swekey_SetRndTokenServer($server)
{
global $gSwekeyRndTokenServer;
if (empty($server)) {
$gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;
} else {
$gSwekeyRndTokenServer = $server;
}
}
/**
* Change the address of the Satus server.
* If $server is empty the default value 'http://auth-status.musbe.net' will be used
*
* @param server The protocol and hostname to use
*
* @access public
*/
function Swekey_SetStatusServer($server)
{
global $gSwekeyStatusServer;
if (empty($server)) {
$gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;
} else {
$gSwekeyStatusServer = $server;
}
}
/**
* Change the certificat file in case of the the severs use https instead of http
*
* @param cafile The path of the crt file to use
*
* @access public
*/
function Swekey_SetCAFile($cafile)
{
global $gSwekeyCA;
$gSwekeyCA = $cafile;
}
/**
* Enable or disable the random token caching
* Because everybody has full access to the cache file, it can be a DOS vulnerability
* So disable it if you are running in a non secure enviromnement
*
* @param $enable
*
* @access public
*/
function Swekey_EnableTokenCache($enable)
{
global $gSwekeyTokenCacheEnabled;
$gSwekeyTokenCacheEnabled = ! empty($enable);
}
/**
* Return the last error.
*
* @return The Last Error
* @access public
*/
function Swekey_GetLastError()
{
global $gSwekeyLastError;
return $gSwekeyLastError;
}
/**
* Return the last result.
*
* @return The Last Error
* @access public
*/
function Swekey_GetLastResult()
{
global $gSwekeyLastResult;
return $gSwekeyLastResult;
}
/**
* Send a synchronous request to the server.
* This function manages timeout then will not block if one of the server is down
*
* @param url The url to get
* @param response_code The response code
*
* @return The body of the response or "" in case of error
* @access private
*/
function Swekey_HttpGet($url, &$response_code)
{
global $gSwekeyLastError;
$gSwekeyLastError = 0;
global $gSwekeyLastResult;
$gSwekeyLastResult = "<not set>";
// use curl if available
if (function_exists('curl_init')) {
$sess = curl_init($url);
if (substr($url, 0, 8) == "https://") {
global $gSwekeyCA;
if (! empty($gSwekeyCA)) {
if (file_exists($gSwekeyCA)) {
if (! curl_setopt($sess, CURLOPT_CAINFO, $gSwekeyCA)) {
error_log("SWEKEY_ERROR:Could not set CA file : ".curl_error($sess));
} else {
$caFileOk = true;
}
} else {
error_log("SWEKEY_ERROR:Could not find CA file $gSwekeyCA getting $url");
}
}
curl_setopt($sess, CURLOPT_SSL_VERIFYHOST, '2');
curl_setopt($sess, CURLOPT_SSL_VERIFYPEER, '2');
curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '20');
curl_setopt($sess, CURLOPT_TIMEOUT, '20');
} else {
curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '3');
curl_setopt($sess, CURLOPT_TIMEOUT, '5');
}
curl_setopt($sess, CURLOPT_RETURNTRANSFER, '1');
$res=curl_exec($sess);
$response_code = curl_getinfo($sess, CURLINFO_HTTP_CODE);
$curlerr = curl_error($sess);
curl_close($sess);
if ($response_code == 200) {
$gSwekeyLastResult = $res;
return $res;
}
if (! empty($response_code)) {
$gSwekeyLastError = $response_code;
error_log("SWEKEY_ERROR:Error $gSwekeyLastError ($curlerr) getting $url");
return "";
}
$response_code = 408; // Request Timeout
$gSwekeyLastError = $response_code;
error_log("SWEKEY_ERROR:Error $curlerr getting $url");
return "";
}
// use pecl_http if available
if (class_exists('HttpRequest')) {
// retry if one of the server is down
for ($num=1; $num <= 3; $num++ ) {
$r = new HttpRequest($url);
$options = array('timeout' => '3');
if (substr($url, 0, 6) == "https:") {
$sslOptions = array();
$sslOptions['verifypeer'] = true;
$sslOptions['verifyhost'] = true;
$capath = __FILE__;
$name = strrchr($capath, '/');
// windows
if (empty($name)) {
$name = strrchr($capath, '\\');
}
$capath = substr($capath, 0, strlen($capath) - strlen($name) + 1).'musbe-ca.crt';
if (! empty($gSwekeyCA)) {
$sslOptions['cainfo'] = $gSwekeyCA;
}
$options['ssl'] = $sslOptions;
}
$r->setOptions($options);
// try
{
$reply = $r->send();
$res = $reply->getBody();
$info = $r->getResponseInfo();
$response_code = $info['response_code'];
if ($response_code != 200) {
$gSwekeyLastError = $response_code;
error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url);
return "";
}
$gSwekeyLastResult = $res;
return $res;
}
// catch (HttpException $e)
// {
// error_log("SWEKEY_WARNING:HttpException ".$e." getting ".$url);
// }
}
$response_code = 408; // Request Timeout
$gSwekeyLastError = $response_code;
error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url);
return "";
}
global $http_response_header;
$res = @file_get_contents($url);
$response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0
if ($response_code == 200) {
$gSwekeyLastResult = $res;
return $res;
}
$gSwekeyLastError = $response_code;
error_log("SWEKEY_ERROR:Error ".$response_code." getting ".$url);
return "";
}
/**
* Get a Random Token from a Token Server
* The RT is a 64 vhars hexadecimal value
* You should better use Swekey_GetFastRndToken() for performance
* @access public
*/
function Swekey_GetRndToken()
{
global $gSwekeyRndTokenServer;
return Swekey_HttpGet($gSwekeyRndTokenServer.'/FULL-RND-TOKEN', $response_code);
}
/**
* Get a Half Random Token from a Token Server
* The RT is a 64 vhars hexadecimal value
* Use this value if you want to make your own Swekey_GetFastRndToken()
* @access public
*/
function Swekey_GetHalfRndToken()
{
global $gSwekeyRndTokenServer;
return Swekey_HttpGet($gSwekeyRndTokenServer.'/HALF-RND-TOKEN', $response_code);
}
/**
* Get a Half Random Token
* The RT is a 64 vhars hexadecimal value
* This function get a new random token and reuse it.
* Token are refetched from the server only once every 30 seconds.
* You should always use this function to get half random token.
* @access public
*/
function Swekey_GetFastHalfRndToken()
{
global $gSwekeyTokenCacheEnabled;
$res = "";
$cachefile = "";
// We check if we have a valid RT is the session
if (isset($_SESSION['rnd-token-date'])) {
if (time() - $_SESSION['rnd-token-date'] < 30) {
$res = $_SESSION['rnd-token'];
}
}
// If not we try to get it from a temp file (PHP >= 5.2.1 only)
if (strlen($res) != 32 && $gSwekeyTokenCacheEnabled) {
if (function_exists('sys_get_temp_dir')) {
$tempdir = sys_get_temp_dir();
$cachefile = $tempdir."/swekey-rnd-token-".get_current_user();
$modif = filemtime($cachefile);
if ($modif != false) {
if (time() - $modif < 30) {
$res = @file_get_contents($cachefile);
if (strlen($res) != 32) {
$res = "";
} else {
$_SESSION['rnd-token'] = $res;
$_SESSION['rnd-token-date'] = $modif;
}
}
}
}
}
// If we don't have a valid RT here we have to get it from the server
if (strlen($res) != 32) {
$res = substr(Swekey_GetHalfRndToken(), 0, 32);
$_SESSION['rnd-token'] = $res;
$_SESSION['rnd-token-date'] = time();
if (! empty($cachefile)) {
// we unlink the file so no possible tempfile race attack
unlink($cachefile);
$file = fopen($cachefile, "x");
if ($file != false) {
@fwrite($file, $res);
@fclose($file);
}
}
}
return $res."00000000000000000000000000000000";
}
/**
* Get a Random Token
* The RT is a 64 vhars hexadecimal value
* This function generates a unique random token for each call but call the
* server only once every 30 seconds.
* You should always use this function to get random token.
* @access public
*/
function Swekey_GetFastRndToken()
{
$res = Swekey_GetFastHalfRndToken();
if (strlen($res) == 64) {
return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" . mt_rand() . date(DATE_ATOM)));
}
return "";
}
/**
* Checks that an OTP generated by a Swekey is valid
*
* @param id The id of the swekey
* @param rt The random token used to generate the otp
* @param otp The otp generated by the swekey
*
* @return true or false
* @access public
*/
function Swekey_CheckOtp($id, $rt, $otp)
{
global $gSwekeyCheckServer;
$res = Swekey_HttpGet($gSwekeyCheckServer.'/CHECK-OTP/'.$id.'/'.$rt.'/'.$otp, $response_code);
return $response_code == 200 && $res == "OK";
}
/**
* Values that are associated with a key.
* The following values can be returned by the Swekey_GetStatus() function
*/
define("SWEKEY_STATUS_OK", 0);
define("SWEKEY_STATUS_NOT_FOUND", 1); // The key does not exist in the db
define("SWEKEY_STATUS_INACTIVE", 2); // The key has never been activated
define("SWEKEY_STATUS_LOST", 3); // The user has lost his key
define("SWEKEY_STATUS_STOLEN", 4); // The key was stolen
define("SWEKEY_STATUS_FEE_DUE", 5); // The annual fee was not paid
define("SWEKEY_STATUS_OBSOLETE", 6); // The hardware is no longer supported
define("SWEKEY_STATUS_UNKOWN", 201); // We could not connect to the authentication server
/**
* Values that are associated with a key.
* The Javascript Api can also return the following values
*/
define("SWEKEY_STATUS_REPLACED", 100); // This key has been replaced by a backup key
define("SWEKEY_STATUS_BACKUP_KEY", 101); // This key is a backup key that is not activated yet
define("SWEKEY_STATUS_NOTPLUGGED", 200); // This key is not plugged in the computer
/**
* Return the text corresponding to the integer status of a key
*
* @param status The status
*
* @return The text corresponding to the status
* @access public
*/
function Swekey_GetStatusStr($status)
{
switch($status)
{
case SWEKEY_STATUS_OK :
return 'OK';
case SWEKEY_STATUS_NOT_FOUND :
return 'Key does not exist in the db';
case SWEKEY_STATUS_INACTIVE :
return 'Key not activated';
case SWEKEY_STATUS_LOST :
return 'Key was lost';
case SWEKEY_STATUS_STOLEN :
return 'Key was stolen';
case SWEKEY_STATUS_FEE_DUE :
return 'The annual fee was not paid';
case SWEKEY_STATUS_OBSOLETE :
return 'Key no longer supported';
case SWEKEY_STATUS_REPLACED :
return 'This key has been replaced by a backup key';
case SWEKEY_STATUS_BACKUP_KEY :
return 'This key is a backup key that is not activated yet';
case SWEKEY_STATUS_NOTPLUGGED :
return 'This key is not plugged in the computer';
case SWEKEY_STATUS_UNKOWN :
return 'Unknow Status, could not connect to the authentication server';
}
return 'unknown status '.$status;
}
/**
* If your web site requires a key to login you should check that the key
* is still valid (has not been lost or stolen) before requiring it.
* A key can be authenticated only if its status is SWEKEY_STATUS_OK
*
* @param id The id of the swekey
*
* @return The status of the swekey
* @access public
*/
function Swekey_GetStatus($id)
{
global $gSwekeyStatusServer;
$res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code);
if ($response_code == 200) {
return intval($res);
}
return SWEKEY_STATUS_UNKOWN;
}
?>