1
0
mirror of https://github.com/Yubico/yubikey-val.git synced 2024-11-29 00:24:13 +01:00

Merge branch 'master' of github.com:Yubico/yubikey-val-server-php

Conflicts:
	ykval-synclib.php
This commit is contained in:
Klas Lindfors 2012-06-11 12:54:55 +02:00
commit 060b35453d
16 changed files with 237 additions and 235 deletions

View File

@ -29,7 +29,7 @@ $myLog = new Log($logname);
$db=new Db($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$logname . ':db');
if (!$db->connect()) {

View File

@ -64,7 +64,7 @@ function debug() {
}
// Return eg. 2008-11-21T06:11:55Z0711
//
//
function getUTCTimeStamp() {
date_default_timezone_set('UTC');
$tiny = substr(microtime(false), 2, 3);
@ -72,7 +72,7 @@ function getUTCTimeStamp() {
}
# NOTE: When we evolve to using general DB-interface, this functinality
# should be moved there.
# should be moved there.
function DbTimeToUnix($db_time)
{
$unix=strptime($db_time, '%F %H:%M:%S');
@ -82,14 +82,14 @@ function DbTimeToUnix($db_time)
function UnixToDbTime($unix)
{
return date('Y-m-d H:i:s', $unix);
}
}
// Sign a http query string in the array of key-value pairs
// return b64 encoded hmac hash
function sign($a, $apiKey) {
ksort($a);
$qs = urldecode(http_build_query($a));
// the TRUE at the end states we want the raw value, not hexadecimal form
$hmac = hash_hmac('sha1', utf8_encode($qs), $apiKey, true);
$hmac = base64_encode($hmac);
@ -97,7 +97,7 @@ function sign($a, $apiKey) {
debug('SIGN: ' . $qs . ' H=' . $hmac);
return $hmac;
} // sign an array of query string
function hex2b64 ($hex_str) {
@ -115,7 +115,7 @@ function modhex2b64 ($modhex_str) {
// The request are sent asynchronously. Some of the URLs can fail
// with unknown host, connection errors, or network timeout, but as
// long as one of the URLs given work, data will be returned. If all
// URLs fail, data from some URL that did not match parameter $match
// URLs fail, data from some URL that did not match parameter $match
// (defaults to ^OK) is returned, or if all URLs failed, false.
function retrieveURLasync ($urls, $ans_req=1, $match="^OK", $returl=False) {
$mh = curl_multi_init();
@ -165,11 +165,11 @@ function retrieveURLasync ($urls, $ans_req=1, $match="^OK", $returl=False) {
curl_close ($h);
}
curl_multi_close ($mh);
if ($ans_count==1) return $ans_arr[0];
else return $ans_arr;
}
curl_multi_remove_handle ($mh, $info['handle']);
curl_close ($info['handle']);
unset ($ch[$info['handle']]);

View File

@ -8,13 +8,13 @@ $baseParams['__YKVAL_DB_PW__'] = 'lab';
$baseParams['__YKVAL_DB_OPTIONS__'] = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
# For the validation server sync
$baseParams['__YKVAL_SYNC_POOL__'] = array("http://api2.example.com/wsapi/2.0/sync",
"http://api3.example.com/wsapi/2.0/sync",
$baseParams['__YKVAL_SYNC_POOL__'] = array("http://api2.example.com/wsapi/2.0/sync",
"http://api3.example.com/wsapi/2.0/sync",
"http://api4.example.com/wsapi/2.0/sync");
# An array of IP addresses allowed to issue sync requests
# NOTE: You must use IP addresses here.
$baseParams['__YKVAL_ALLOWED_SYNC_POOL__'] = array("1.2.3.4",
"2.3.4.5",
$baseParams['__YKVAL_ALLOWED_SYNC_POOL__'] = array("1.2.3.4",
"2.3.4.5",
"3.4.5.6");
# Specify how often the sync daemon awakens

View File

@ -18,7 +18,7 @@ class Db
* @param string $user Database user
* @param string $pwd Database password
* @param string $name Database table name
* @return void
* @return void
*
*/
public function __construct($db_dsn, $db_username, $db_password, $db_options, $name='ykval-db')
@ -39,7 +39,7 @@ class Db
/**
* function to convert Db timestamps to unixtime(s)
*
* @param string $updated Database timestamp
* @param string $updated Database timestamp
* @return int Timestamp in unixtime format
*
*/
@ -53,7 +53,7 @@ class Db
/**
* function to compute delta (s) between 2 Db timestamps
*
* @param string $first Database timestamp 1
* @param string $first Database timestamp 1
* @param string $second Database timestamp 2
* @return int Deltatime (s)
*
@ -73,7 +73,7 @@ class Db
{
$this->dbh=NULL;
}
/**
* function to check if database is connected
*
@ -109,7 +109,7 @@ class Db
}
if($this->isConnected()) {
$this->myLog->log(LOG_DEBUG, 'DB query is: ' . $query);
try {
$this->result = $this->dbh->query($query);
} catch (PDOException $e) {
@ -154,8 +154,8 @@ class Db
$query = rtrim($query, ",") . " WHERE " . $k . " = '" . $v . "'";
// Insert UPDATE statement at beginning
$query = "UPDATE " . $table . " SET " . $query;
$query = "UPDATE " . $table . " SET " . $query;
return $this->query($query, false);
}
@ -199,11 +199,11 @@ class Db
$query = rtrim($query, ",") . " WHERE " . $k . " = '" . $v . "' and " . $condition;
// Insert UPDATE statement at beginning
$query = "UPDATE " . $table . " SET " . $query;
$query = "UPDATE " . $table . " SET " . $query;
return $this->query($query, false);
}
/**
* Function to update row in database based on a condition.
@ -258,7 +258,7 @@ or false on failure.
}
/**
* main function used to get rows from Db table.
* main function used to get rows from Db table.
*
* @param string $table Database table to update row in
* @param string $key Column to select rows by
@ -274,7 +274,7 @@ or false on failure.
}
/**
* main function used to get rows by multiple key=>value pairs from Db table.
* main function used to get rows by multiple key=>value pairs from Db table.
*
* @param string $table Database table to update row in
* @param array $where Array with column=>values to select rows by
@ -295,7 +295,7 @@ or false on failure.
$query.= " *";
}
$query.= " FROM " . $table;
if ($where!=null){
if ($where!=null){
foreach ($where as $key=>$value) {
if ($key!=null) {
if ($value!=null) $match.= " ". $key . " = '" . $value . "' and";
@ -311,12 +311,12 @@ or false on failure.
$result = $this->query($query, true);
if (!$result) return false;
if ($nr==1) {
$row = $result->fetch(PDO::FETCH_ASSOC);
$result->closeCursor();
return $row;
}
}
else {
$collection=array();
while($row = $result->fetch(PDO::FETCH_ASSOC)){
@ -329,7 +329,7 @@ or false on failure.
}
/**
* main function used to delete rows by multiple key=>value pairs from Db table.
* main function used to delete rows by multiple key=>value pairs from Db table.
*
* @param string $table Database table to delete row in
* @param array $where Array with column=>values to select rows by
@ -343,7 +343,7 @@ or false on failure.
{
$query="DELETE";
$query.= " FROM " . $table;
if ($where!=null){
if ($where!=null){
$query.= " WHERE";
foreach ($where as $key=>$value) {
$query.= " ". $key . " = '" . $value . "' and";
@ -358,10 +358,10 @@ or false on failure.
/**
* Function to do a custom query on database connection
* Function to do a custom query on database connection
*
* @param string $query Database query
* @return mixed
* @return mixed
*
*/
public function customQuery($query)
@ -370,14 +370,14 @@ or false on failure.
}
/**
* Function to do a custom query on database connection
* Function to do a custom query on database connection
*
* @return int number of rows affected by last statement or 0 if database connection is not functional.
*
*/
public function rowCount()
{
if($this->result) {
if($this->result) {
$count=count($this->result->fetchAll());
$this->result->closeCursor();
return $count;
@ -387,8 +387,8 @@ or false on failure.
}
/**
* helper function used to get rows from Db table in reversed order.
* defaults to obtaining 1 row.
* helper function used to get rows from Db table in reversed order.
* defaults to obtaining 1 row.
*
* @param string $table Database table to update row in
* @param string $key Column to select rows by
@ -403,8 +403,8 @@ or false on failure.
}
/**
* helper function used to get rows from Db table in standard order.
* defaults to obtaining 1 row.
* helper function used to get rows from Db table in standard order.
* defaults to obtaining 1 row.
*
* @param string $table Database table to update row in
* @param string $key Column to select rows by
@ -417,7 +417,7 @@ or false on failure.
{
return Db::findBy($table, $key, $value, $nr);
}
}

View File

@ -13,13 +13,13 @@ $myLog = new Log($logname);
$db=new Db($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$logname . ':db');
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
}
}
$result = $db->customQuery("select id, active, created, secret, email, notes, otp from clients order by id");
while($row = $result->fetch(PDO::FETCH_ASSOC)){

View File

@ -13,13 +13,13 @@ $myLog = new Log($logname);
$db=new Db($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$logname . ':db');
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
}
}
$result=$db->customQuery("SELECT active, created, modified, yk_publicname, yk_counter, yk_use, yk_low, yk_high, nonce, notes FROM yubikeys ORDER BY yk_publicname");
while($row = $result->fetch(PDO::FETCH_ASSOC)){

View File

@ -13,26 +13,26 @@ $myLog = new Log($logname);
$db=new Db($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$logname . ':db');
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
}
}
while ($res=fgetcsv(STDIN, 0, "\t")) {
$params=array("id"=>$res[0],
"active"=>$res[1],
"created"=>$res[2],
"secret"=>$res[3],
"email"=>$res[4],
"notes"=>$res[5],
$params=array("id"=>$res[0],
"active"=>$res[1],
"created"=>$res[2],
"secret"=>$res[3],
"email"=>$res[4],
"notes"=>$res[5],
"otp"=>$res[6]);
$query="SELECT * FROM clients WHERE id='" . $params['id'] . "'";
$result=$db->customQuery($query);
if(!$result->fetch(PDO::FETCH_ASSOC)) {
@ -46,7 +46,7 @@ while ($res=fgetcsv(STDIN, 0, "\t")) {
"'" . $params['email'] . "'," .
"'" . $params['notes'] . "'," .
"'" . $params['otp'] . "')";
if(!$db->customQuery($query)){
$myLog->log(LOG_ERR, "Failed to insert new client with query " . $query);
error_log("Failed to insert new client with query " . $query);

View File

@ -13,29 +13,29 @@ $myLog = new Log($logname);
$db=new Db($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$logname . ':db');
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
}
}
while ($res=fgetcsv(STDIN, 0, "\t")) {
$params=array("active"=>$res[0],
"created"=>$res[1],
"modified"=>$res[2],
"yk_publicname"=>$res[3],
"yk_counter"=>$res[4],
"yk_use"=>$res[5],
"yk_low"=>$res[6],
"yk_high"=>$res[7],
$params=array("active"=>$res[0],
"created"=>$res[1],
"modified"=>$res[2],
"yk_publicname"=>$res[3],
"yk_counter"=>$res[4],
"yk_use"=>$res[5],
"yk_low"=>$res[6],
"yk_high"=>$res[7],
"nonce"=>$res[8],
"notes"=>$res[9]);
$query="SELECT * FROM yubikeys WHERE yk_publicname='" . $params['yk_publicname'] . "'";
$result=$db->customQuery($query);
if($result->fetch(PDO::FETCH_ASSOC)) {
@ -52,13 +52,13 @@ while ($res=fgetcsv(STDIN, 0, "\t")) {
"WHERE yk_publicname='" . $params['yk_publicname'] . "' AND " .
"(".$params['yk_counter'].">yk_counter or (".$params['yk_counter']."=yk_counter and " .
$params['yk_use'] . ">yk_use))";
if(!$db->customQuery($query)) {
$myLog->log(LOG_ERR, "Failed to update yk_publicname with query " . $query);
error_log("Failed to update yk_publicname with query " . $query);
exit(1);
}
} else {
// We didn't have the yk_publicname in database so we need to do insert instead
$query="INSERT INTO yubikeys " .
@ -73,7 +73,7 @@ while ($res=fgetcsv(STDIN, 0, "\t")) {
"'" . $params['yk_high'] . "'," .
"'" . $params['nonce'] . "'," .
"'" . $params['notes'] . "')";
if(!$db->customQuery($query)){
$myLog->log(LOG_ERR, "Failed to insert new yk_publicname with query " . $query);
error_log("Failed to insert new yk_publicname with query " . $query);

View File

@ -2,29 +2,29 @@
class Log
{
function __construct($name='ykval')
{
$this->name=$name;
$this->fields=array();
$this->LOG_LEVELS = array(LOG_EMERG=>'LOG_EMERG',
LOG_ALERT=>'LOG_ALERT',
LOG_CRIT=>'LOG_CRIT',
LOG_ERR=>'LOG_ERR',
LOG_WARNING=>'LOG_WARNING',
LOG_NOTICE=>'LOG_NOTICE',
LOG_INFO=>'LOG_INFO',
$this->LOG_LEVELS = array(LOG_EMERG=>'LOG_EMERG',
LOG_ALERT=>'LOG_ALERT',
LOG_CRIT=>'LOG_CRIT',
LOG_ERR=>'LOG_ERR',
LOG_WARNING=>'LOG_WARNING',
LOG_NOTICE=>'LOG_NOTICE',
LOG_INFO=>'LOG_INFO',
LOG_DEBUG=>'LOG_DEBUG');
openlog("ykval", LOG_PID, LOG_LOCAL0);
}
function addField($name, $value)
function addField($name, $value)
{
$this->fields[$name]=$value;
}
function log($priority, $message, $arr=null){
if (is_array($arr)) {
foreach($arr as $key=>$value){
@ -36,13 +36,13 @@ class Log
foreach ($this->fields as $field=>$value) {
$msg_fields .= "[" . $value . "] ";
}
syslog($priority,
syslog($priority,
$this->LOG_LEVELS[$priority] . ':' .
$this->name . ':' .
$msg_fields .
$this->name . ':' .
$msg_fields .
$message);
}
}
?>

View File

@ -4,8 +4,8 @@
set_include_path(get_include_path() . PATH_SEPARATOR .
"/etc/ykval:/usr/share/ykval");
require_once 'ykval-synclib.php';
require_once 'ykval-config.php';
require_once 'ykval-synclib.php';
require_once 'ykval-log.php';
if ($argc==2 && strcmp($argv[1], "autoconf") == 0) {

View File

@ -1,4 +1,4 @@
<?php
<?php
header("content-type: text/plain");

View File

@ -12,18 +12,18 @@ if ($argc==2 && strcmp($argv[1], "install")!=0) {
set_include_path(get_include_path() . PATH_SEPARATOR . $argv[1]);
}
require_once "System/Daemon.php";
require_once "System/Daemon.php";
$appname="ykval-queue";
System_Daemon::setOption("appName", $appname);
System_Daemon::setOption("appDescription", "Yubico val-server sync daemon");
System_Daemon::setOption("authorName", "olov@yubico.com");
System_Daemon::setOption("authorEmail", "olov@yubico.com");
System_Daemon::setOption("appName", $appname);
System_Daemon::setOption("appDescription", "Yubico val-server sync daemon");
System_Daemon::setOption("authorName", "olov@yubico.com");
System_Daemon::setOption("authorEmail", "olov@yubico.com");
if ($argc==2 && strcmp($argv[1], "install")==0) {
$autostart_path = System_Daemon::writeAutoRun();
if ($autostart_path!=1){
if ($autostart_path!=1){
echo "Successfully created start script at " . $autostart_path . "\n";
echo "To start daemon use: /etc/init.d/".$appname." start\n";
} else {
@ -46,7 +46,7 @@ $sl = new SyncLib('ykval-queue:synclib');
$res==0;
while ($res==0) {
$sl->reSync($baseParams['__YKVAL_SYNC_OLD_LIMIT__'],
$sl->reSync($baseParams['__YKVAL_SYNC_OLD_LIMIT__'],
$baseParams['__YKVAL_SYNC_RESYNC_TIMEOUT__']);
$res=sleep($baseParams['__YKVAL_SYNC_INTERVAL__']);
}

View File

@ -26,7 +26,7 @@ if ($do != "enable" && $do != "disable") {
$db = new Db($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
'ykval-revoke:db');
if (!$db->connect()) {
logdie("ERROR Database connect error");

View File

@ -20,7 +20,7 @@ if (! $sync->isConnected()) {
exit;
}
#
#
# Verify that request comes from valid server
#
@ -77,7 +77,7 @@ $myLog->addField('otp', $syncParams['otp']);
$sync->addField('otp', $syncParams['otp']);
#
# Verify correctness of input parameters
# Verify correctness of input parameters
#
foreach (array('modified') as $param) {
@ -106,27 +106,27 @@ foreach (array('yk_counter', 'yk_use', 'yk_high', 'yk_low') as $param) {
$yk_publicname = $syncParams['yk_publicname'];
$localParams = $sync->getLocalParams($yk_publicname);
if (!$localParams) {
$myLog->log(LOG_NOTICE, 'Invalid Yubikey ' . $yk_publicname);
$myLog->log(LOG_NOTICE, 'Refusing sync of invalid Yubikey ' . $yk_publicname);
sendResp(S_BACKEND_ERROR, $apiKey);
exit;
}
if ($localParams['active'] != 1) {
$myLog->log(LOG_NOTICE, 'De-activated Yubikey ' . $yk_publicname);
$myLog->log(LOG_NOTICE, 'Refusing sync of de-activated Yubikey ' . $yk_publicname);
sendResp(S_BAD_OTP, $apiKey);
exit;
}
/* Conditional update local database */
$sync->updateDbCounters($syncParams);
$sync->updateDbCounters($syncParams);
$myLog->log(LOG_DEBUG, 'Local params ' , $localParams);
$myLog->log(LOG_DEBUG, 'Sync request params ' , $syncParams);
#
# Compare sync and local counters and generate warnings according to
#
# Compare sync and local counters and generate warnings according to
#
# http://code.google.com/p/yubikey-val-server-php/wiki/ServerReplicationProtocol
#
@ -143,7 +143,7 @@ if ($sync->countersEqual($localParams, $syncParams)) {
$syncParams['nonce']==$localParams['nonce']) {
$myLog->log(LOG_NOTICE, 'Sync request unnessecarily sent');
}
if ($syncParams['modified']!=$localParams['modified'] &&
$syncParams['nonce']==$localParams['nonce']) {
$deltaModified = $syncParams['modified'] - $localParams['modified'];
@ -156,7 +156,7 @@ if ($sync->countersEqual($localParams, $syncParams)) {
}
$extra=array('modified'=>$localParams['modified'],
'nonce'=>$localParams['nonce'],
'yk_publicname'=>$yk_publicname,

View File

@ -19,10 +19,10 @@ class SyncLib
$this->db=new Db($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$logname . ':db');
$this->isConnected=$this->db->connect();
$this->server_nonce=md5(uniqid(rand()));
$this->server_nonce=md5(uniqid(rand()));
}
@ -32,7 +32,7 @@ class SyncLib
$this->db->addField($name, $value);
}
function isConnected()
function isConnected()
{
return $this->isConnected;
}
@ -42,11 +42,11 @@ class SyncLib
$unix=strptime($db_time, '%F %H:%M:%S');
return mktime($unix[tm_hour], $unix[tm_min], $unix[tm_sec], $unix[tm_mon]+1, $unix[tm_mday], $unix[tm_year]+1900);
}
function UnixToDbTime($unix)
{
return date('Y-m-d H:i:s', $unix);
}
}
function getServer($index)
{
@ -91,11 +91,11 @@ class SyncLib
return $out[0];
}
public function localParamsFromInfoString($info)
public function localParamsFromInfoString($info)
{
$out=explode(",", $info);
parse_str($out[1], $params);
return array('yk_counter'=>$params['local_counter'],
return array('yk_counter'=>$params['local_counter'],
'yk_use'=>$params['local_use']);
}
@ -105,14 +105,14 @@ class SyncLib
$info=$this->createInfoString($otpParams, $localParams);
$this->otpParams = $otpParams;
$this->localParams = $localParams;
$queued=time();
$res=True;
foreach ($this->syncServers as $server) {
if(! $this->db->save('queue', array('queued'=>$queued,
'modified'=>$otpParams['modified'],
'otp'=>$otpParams['otp'],
'modified'=>$otpParams['modified'],
'otp'=>$otpParams['otp'],
'server'=>$server,
'server_nonce'=>$this->server_nonce,
'info'=>$info))) $res=False;
@ -132,9 +132,9 @@ class SyncLib
if ($params) $logMsg .= ' modified=' . $params['modified'] .
' nonce=' . $params['nonce'] .
' yk_publicname=' . $params['yk_publicname'] .
' yk_counter=' . $params['yk_counter'] .
' yk_use=' . $params['yk_use'] .
' yk_high=' . $params['yk_high'] .
' yk_counter=' . $params['yk_counter'] .
' yk_use=' . $params['yk_use'] .
' yk_high=' . $params['yk_high'] .
' yk_low=' . $params['yk_low'];
if ($this->myLog) $this->myLog->log($priority, $logMsg);
else error_log("Warning: myLog uninitialized in ykval-synclib.php. Message is " . $logMsg);
@ -147,7 +147,7 @@ class SyncLib
if (!$res) {
$this->log(LOG_NOTICE, 'Discovered new identity ' . $yk_publicname);
$this->db->save('yubikeys', array('active'=>1,
$this->db->save('yubikeys', array('active'=>1,
'created'=>time(),
'modified'=>-1,
'yk_publicname'=>$yk_publicname,
@ -164,11 +164,11 @@ class SyncLib
'nonce'=>$res['nonce'],
'active'=>$res['active'],
'yk_publicname'=>$yk_publicname,
'yk_counter'=>$res['yk_counter'],
'yk_counter'=>$res['yk_counter'],
'yk_use'=>$res['yk_use'],
'yk_high'=>$res['yk_high'],
'yk_low'=>$res['yk_low']);
$this->log(LOG_INFO, "yubikey found in db ", $localParams);
return $localParams;
} else {
@ -230,18 +230,18 @@ class SyncLib
if (isset($params['yk_publicname'])) {
$condition='('.$params['yk_counter'].'>yk_counter or ('.$params['yk_counter'].'=yk_counter and ' .
$params['yk_use'] . '>yk_use))' ;
if(! $this->db->conditionalUpdateBy('yubikeys', 'yk_publicname', $params['yk_publicname'],
array('modified'=>$params['modified'],
'yk_counter'=>$params['yk_counter'],
if(! $this->db->conditionalUpdateBy('yubikeys', 'yk_publicname', $params['yk_publicname'],
array('modified'=>$params['modified'],
'yk_counter'=>$params['yk_counter'],
'yk_use'=>$params['yk_use'],
'yk_low'=>$params['yk_low'],
'yk_high'=>$params['yk_high'],
'nonce'=>$params['nonce']),
'yk_high'=>$params['yk_high'],
'nonce'=>$params['nonce']),
$condition))
{
$this->log(LOG_CRIT, 'failed to update internal DB with new counters');
return false;
} else
} else
{
if ($this->db->rowCount()>0) $this->log(LOG_INFO, "updated database ", $params);
else $this->log(LOG_INFO, 'database not updated', $params);
@ -249,7 +249,7 @@ class SyncLib
}
} else return false;
}
public function countersHigherThan($p1, $p2)
{
if ($p1['yk_counter'] > $p2['yk_counter'] ||
@ -257,7 +257,7 @@ class SyncLib
$p1['yk_use'] > $p2['yk_use'])) return true;
else return false;
}
public function countersHigherThanOrEqual($p1, $p2)
{
if ($p1['yk_counter'] > $p2['yk_counter'] ||
@ -270,17 +270,17 @@ class SyncLib
return ($p1['yk_counter']==$p2['yk_counter']) && ($p1['yk_use']==$p2['yk_use']);
}
public function deleteQueueEntry($answer)
public function deleteQueueEntry($answer)
{
preg_match('/url=(.*)\?/', $answer, $out);
$server=$out[1];
$this->log(LOG_INFO, "deleting server=" . $server .
$this->log(LOG_INFO, "deleting server=" . $server .
" modified=" . $this->otpParams['modified'] .
" server_nonce=" . $this->server_nonce);
$this->db->deleteByMultiple('queue',
$this->db->deleteByMultiple('queue',
array("modified"=>$this->otpParams['modified'],
"server_nonce"=>$this->server_nonce,
"server_nonce"=>$this->server_nonce,
'server'=>$server));
}
@ -290,20 +290,20 @@ class SyncLib
/* Loop over all unique servers in queue */
$queued_limit=time()-$older_than;
$res=$this->db->customQuery("select distinct server from queue WHERE queued < " . $queued_limit . " or queued is null");
foreach ($res as $my_server) {
$this->log(LOG_INFO, "Sending queue request to server on server " . $my_server['server']);
$res=$this->db->customQuery("select * from queue WHERE (queued < " . $queued_limit . " or queued is null) and server='" . $my_server['server'] . "'");
$ch = curl_init();
while ($entry=$res->fetch(PDO::FETCH_ASSOC)) {
$this->log(LOG_INFO, "server=" . $entry['server'] . " , info=" . $entry['info']);
$url=$entry['server'] .
$url=$entry['server'] .
"?otp=" . $entry['otp'] .
"&modified=" . $entry['modified'] .
"&" . $this->otpPartFromInfoString($entry['info']);
/* Send out sync request */
$this->log(LOG_DEBUG, 'url is ' . $url);
curl_setopt($ch, CURLOPT_URL, $url);
@ -313,101 +313,103 @@ class SyncLib
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
$response = curl_exec($ch);
if ($response==False) {
$this->log(LOG_NOTICE, 'Timeout. Stopping queue resync for server ' . $my_server['server']);
break;
}
if (preg_match("/status=OK/", $response)) {
$resParams=$this->parseParamsFromMultiLineString($response);
$this->log(LOG_DEBUG, "response contains ", $resParams);
/* Update database counters */
$this->updateDbCounters($resParams);
/* Retrieve info from entry info string */
$validationParams=$this->localParamsFromInfoString($entry['info']);
$otpParams=$this->otpParamsFromInfoString($entry['info']);
$localParams=$this->getLocalParams($otpParams['yk_publicname']);
$this->log(LOG_DEBUG, "validation params: ", $validationParams);
$this->log(LOG_DEBUG, "OTP params: ", $otpParams);
/* Check for warnings */
/* Check for warnings */
if ($this->countersHigherThan($validationParams, $resParams)) {
$this->log(LOG_NOTICE, "Remote server out of sync compared to counters at validation request time. ");
}
if ($this->countersHigherThan($resParams, $validationParams)) {
$this->log(LOG_NOTICE, "Local server out of sync compared to counters at validation request time. ");
}
if ($this->countersHigherThan($localParams, $resParams)) {
$this->log(LOG_WARNING, "Remote server out of sync compared to current local counters. ");
}
if ($this->countersHigherThan($resParams, $localParams)) {
$this->log(LOG_WARNING, "Local server out of sync compared to current local counters. Local server updated. ");
}
if ($this->countersHigherThan($resParams, $otpParams)) {
$this->log(LOG_ERR, "Remote server has higher counters than OTP. This response would have marked the OTP as invalid. ");
}
}
elseif ($this->countersEqual($resParams, $otpParams) &&
$resParams['nonce']!=$otpParams['nonce']) {
$this->log(LOG_ERR, "Remote server has equal counters as OTP and nonce differs. This response would have marked the OTP as invalid.");
}
/* Deletion */
$this->log(LOG_INFO, 'deleting queue entry with modified=' . $entry['modified'] .
' server_nonce=' . $entry['server_nonce'] .
' server=' . $entry['server']);
$this->db->deleteByMultiple('queue',
$this->db->deleteByMultiple('queue',
array("modified"=>$entry['modified'],
"server_nonce"=>$entry['server_nonce'],
"server_nonce"=>$entry['server_nonce'],
'server'=>$entry['server']));
} else {
$this->log(LOG_ERR, "Remote server refused our sync request. Check remote server logs.");
}
} /* End of loop over each queue entry for a server */
curl_close($ch);
curl_close($ch);
$res->closeCursor();
} /* End of loop over each distinct server in queue */
return true;
}
public function sync($ans_req, $timeout=1)
public function sync($ans_req, $timeout=1)
{
/*
Construct URLs
*/
$urls=array();
$res=$this->db->findByMultiple('queue', array("modified"=>$this->otpParams['modified'], "server_nonce"=>$this->server_nonce));
foreach ($res as $row) {
$urls[]=$row['server'] .
$urls[]=$row['server'] .
"?otp=" . $row['otp'] .
"&modified=" . $row['modified'] .
"&" . $this->otpPartFromInfoString($row['info']);
}
/*
Send out requests
*/
$ans_arr=$this->retrieveURLasync($urls, $ans_req, $timeout);
if (!is_array($ans_arr)) {
$this->log(LOG_WARNING, 'No responses from validation server pool');
$this->log(LOG_WARNING, 'No responses from validation server pool');
$ans_arr=array();
}
/*
Parse responses
*/
$localParams = $this->localParams;
$this->answers = count($ans_arr);
$this->valid_answers = 0;
foreach ($ans_arr as $answer){
@ -418,71 +420,71 @@ class SyncLib
$this->log(LOG_DEBUG, "OTP contains " , $this->otpParams);
/* Update internal DB (conditional) */
$this->updateDbCounters($resParams);
/* Check for warnings
/* Check for warnings
See http://code.google.com/p/yubikey-val-server-php/wiki/ServerReplicationProtocol
NOTE: We use localParams for validationParams comparison since they are actually the
same in this situation and we have them at hand.
same in this situation and we have them at hand.
*/
if ($this->countersHigherThan($localParams, $resParams)) {
$this->log(LOG_NOTICE, "Remote server out of sync");
}
if ($this->countersHigherThan($resParams, $localParams)) {
$this->log(LOG_NOTICE, "Local server out of sync");
}
if ($this->CountersEqual($resParams, $localParams) &&
if ($this->CountersEqual($resParams, $localParams) &&
$resParams['nonce']!=$localParams['nonce']) {
$this->log(LOG_NOTICE, "Servers out of sync. Nonce differs. ");
}
if ($this->CountersEqual($resParams, $localParams) &&
if ($this->CountersEqual($resParams, $localParams) &&
$resParams['modified']!=$localParams['modified']) {
$this->log(LOG_NOTICE, "Servers out of sync. Modified differs. ");
}
if ($this->countersHigherThan($resParams, $this->otpParams)){
$this->log(LOG_WARNING, 'OTP is replayed. Sync response counters higher than OTP counters.');
}
}
elseif ($this->countersEqual($resParams, $this->otpParams) &&
$resParams['nonce']!=$this->otpParams['nonce']) {
$this->log(LOG_WARNING, 'OTP is replayed. Sync response counters equal to OTP counters and nonce differs.');
} else {
/* The answer is ok since a REPLAY was not indicated */
$this->valid_answers++;
}
/* Delete entry from table */
$this->deleteQueueEntry($answer);
}
/*
/*
NULL queued_time for remaining entries in queue, to allow
daemon to take care of them as soon as possible. */
$this->db->updateBy('queue', 'server_nonce', $this->server_nonce,
array('queued'=>NULL));
/* Return true if valid answers equals required answers.
Since we only obtain the required amount of answers from
retrieveAsync this indicates that all answers were actually valid.
$this->db->updateBy('queue', 'server_nonce', $this->server_nonce,
array('queued'=>NULL));
/* Return true if valid answers equals required answers.
Since we only obtain the required amount of answers from
retrieveAsync this indicates that all answers were actually valid.
Otherwise, return false. */
if ($this->valid_answers==$ans_req) return True;
else return False;
@ -507,7 +509,7 @@ class SyncLib
The request are sent asynchronously. Some of the URLs can fail
with unknown host, connection errors, or network timeout, but as
long as one of the URLs given work, data will be returned. If all
URLs fail, data from some URL that did not match parameter $match
URLs fail, data from some URL that did not match parameter $match
(defaults to ^OK) is returned, or if all URLs failed, false.
*/
function retrieveURLasync ($urls, $ans_req=1, $timeout=1.0) {
@ -517,26 +519,26 @@ class SyncLib
foreach ($urls as $id => $url) {
$this->log(LOG_DEBUG, "url in retrieveURLasync is " . $url);
$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, $url);
curl_setopt($handle, CURLOPT_USERAGENT, "YK-VAL");
curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($handle, CURLOPT_FAILONERROR, true);
curl_setopt($handle, CURLOPT_TIMEOUT, $timeout);
curl_multi_add_handle($mh, $handle);
$ch[$handle] = $handle;
}
$str = false;
$ans_count = 0;
$ans_arr = array();
do {
while (($mrc = curl_multi_exec($mh, $active)) == CURLM_CALL_MULTI_PERFORM)
;
while ($info = curl_multi_info_read($mh)) {
debug ("YK-KSM multi", $info);
if ($info['result'] == CURLE_OK) {
@ -549,27 +551,27 @@ class SyncLib
$ans_count++;
$ans_arr[]="url=" . $cinfo['url'] . "\n" . $str;
}
if ($ans_count >= $ans_req) {
foreach ($ch as $h) {
curl_multi_remove_handle ($mh, $h);
curl_close ($h);
}
curl_multi_close ($mh);
return $ans_arr;
}
curl_multi_remove_handle ($mh, $info['handle']);
curl_close ($info['handle']);
unset ($ch[$info['handle']]);
}
curl_multi_select ($mh);
}
} while($active);
foreach ($ch as $h) {
curl_multi_remove_handle ($mh, $h);
curl_close ($h);
@ -579,7 +581,7 @@ class SyncLib
if ($ans_count>0) return $ans_arr;
else return $str;
}
}
?>

View File

@ -47,12 +47,12 @@ $myLog->addField('otp', $otp);
if ($protocol_version>=2.0) {
$sl = getHttpVal('sl', '');
$timeout = getHttpVal('timeout', '');
$timeout = getHttpVal('timeout', '');
$nonce = getHttpVal('nonce', '');
/* Add nonce to response parameters */
$extra['nonce']= $nonce;
/* Nonce is required from protocol 2.0 */
if(!$nonce) {
$myLog->log(LOG_NOTICE, 'Nonce is missing and protocol version >= 2.0');
@ -62,15 +62,15 @@ if ($protocol_version>=2.0) {
}
/* Sanity check HTTP parameters
/* Sanity check HTTP parameters
* otp: one-time password
* id: client id
* timeout: timeout in seconds to wait for external answers, optional: if absent the server decides
* nonce: random alphanumeric string, 16 to 40 characters long. Must be non-predictable and changing for each request, but need not be cryptographically strong
* sl: "sync level", percentage of external servers that needs to answer (integer 0 to 100), or "fast" or "secure" to use server-configured values
* h: signature (optional)
* timestamp: requests timestamp/counters in response
* otp: one-time password
* id: client id
* timeout: timeout in seconds to wait for external answers, optional: if absent the server decides
* nonce: random alphanumeric string, 16 to 40 characters long. Must be non-predictable and changing for each request, but need not be cryptographically strong
* sl: "sync level", percentage of external servers that needs to answer (integer 0 to 100), or "fast" or "secure" to use server-configured values
* h: signature (optional)
* timestamp: requests timestamp/counters in response
*/
@ -129,7 +129,7 @@ if (isset($nonce) && (strlen($nonce) < 16 || strlen($nonce) > 40)) {
sendResp(S_MISSING_PARAMETER);
exit;
}
if ($sl && (preg_match("/^[0-9]+$/", $sl)==0 || ($sl<0 || $sl>100))) {
$myLog->log(LOG_NOTICE, 'SL is provided but not correct');
sendResp(S_MISSING_PARAMETER);
@ -137,7 +137,7 @@ if ($sl && (preg_match("/^[0-9]+$/", $sl)==0 || ($sl<0 || $sl>100))) {
}
// NOTE: Timestamp parameter is not checked since current protocol says that 1 means request timestamp
// and anything else is discarded.
// and anything else is discarded.
//// Get Client info from DB
//
@ -150,7 +150,7 @@ if ($client <= 0) {
/* Initialize the sync library. Strive to use this instead of custom
DB requests, custom comparisons etc */
DB requests, custom comparisons etc */
$sync = new SyncLib('ykval-verify:synclib');
$sync->addField('ip', $_SERVER['REMOTE_ADDR']);
$sync->addField('otp', $otp);
@ -194,11 +194,11 @@ if ($h != '') {
}
}
/* We need to add necessary parameters not available at earlier protocols after signature is computed.
/* We need to add necessary parameters not available at earlier protocols after signature is computed.
*/
if ($protocol_version<2.0) {
/* We need to create a nonce manually here */
$nonce = md5(uniqid(rand()));
$nonce = md5(uniqid(rand()));
$myLog->log(LOG_INFO, 'protocol version below 2.0. Created nonce ' . $nonce);
}
@ -239,13 +239,13 @@ if ($localParams['active'] != 1) {
/* Build OTP params */
$otpParams=array('modified'=>time(),
'otp'=>$otp,
$otpParams=array('modified'=>time(),
'otp'=>$otp,
'nonce'=>$nonce,
'yk_publicname'=>$devId,
'yk_counter'=>$otpinfo['session_counter'],
'yk_use'=>$otpinfo['session_use'],
'yk_high'=>$otpinfo['high'],
'yk_publicname'=>$devId,
'yk_counter'=>$otpinfo['session_counter'],
'yk_use'=>$otpinfo['session_use'],
'yk_high'=>$otpinfo['high'],
'yk_low'=>$otpinfo['low']);
@ -257,7 +257,7 @@ if ($sync->countersEqual($localParams, $otpParams) &&
exit;
}
/* Check the OTP counters against local db */
/* Check the OTP counters against local db */
if ($sync->countersHigherThanOrEqual($localParams, $otpParams)) {
$sync->log(LOG_WARNING, 'replayed OTP: Local counters higher');
$sync->log(LOG_WARNING, 'replayed OTP: Local counters ', $localParams);
@ -289,7 +289,7 @@ if ($req_answers>0) {
$nr_answers=$sync->getNumberOfAnswers();
$nr_valid_answers=$sync->getNumberOfValidAnswers();
$sl_success_rate=floor(100.0 * $nr_valid_answers / $nr_servers);
} else {
$syncres=true;
$nr_answers=0;
@ -305,7 +305,7 @@ $myLog->log(LOG_INFO, "ykval-verify:notice:synclevel=" . $sl .
" timeout=" . $timeout);
if($syncres==False) {
/* sync returned false, indicating that
/* sync returned false, indicating that
either at least 1 answer marked OTP as invalid or
there were not enough answers */
$myLog->log(LOG_WARNING, "ykval-verify:notice:Sync failed");
@ -319,7 +319,7 @@ if($syncres==False) {
}
}
/* Recreate parameters to make phising test work out
/* Recreate parameters to make phising test work out
TODO: use timefunctionality in deltatime library instead */
$sessionCounter = $otpParams['yk_counter'];
$sessionUse = $otpParams['yk_use'];
@ -345,8 +345,8 @@ if ($sessionCounter == $seenSessionCounter && $sessionUse > $seenSessionUse) {
$elapsed = $now - $lastTime;
$deviation = abs($elapsed - $tsDelta);
// Time delta server might verify multiple OTPS in a row. In such case validation server doesn't
// have time to tick a whole second and we need to avoid division by zero.
// Time delta server might verify multiple OTPS in a row. In such case validation server doesn't
// have time to tick a whole second and we need to avoid division by zero.
if ($elapsed != 0) {
$percent = $deviation/$elapsed;
} else {