diff --git a/tests/DbTest.php b/tests/DbTest.php index 53bdbb4..d76e44d 100644 --- a/tests/DbTest.php +++ b/tests/DbTest.php @@ -17,7 +17,7 @@ class DbTest extends PHPUnit_Framework_TestCase $baseParams['__YKVAL_DB_NAME__']); $this->db->connect(); $this->db->customQuery("drop table unittest"); - $this->db->customQuery("create table unittest (value1 int, value2 int)"); + $this->db->customQuery("create table unittest (id int,value1 int, value2 int)"); } public function test_template() { @@ -37,6 +37,34 @@ class DbTest extends PHPUnit_Framework_TestCase 'value2'=>200)); $this->assertEquals(1, count($res)); } - + + public function testUpdateBy() + { + $this->assertTrue($this->db->save('unittest', array('value1'=>100, + 'value2'=>200))); + $this->db->updateBy('unittest', 'value1', 100, array('value2'=>NULL)); + $res=$this->db->findByMultiple('unittest', array('value1'=>100, + 'value2'=>NULL)); + $this->assertEquals(1, count($res)); + } + public function testFindBy() + { + $this->assertTrue($this->db->save('unittest', array('value1'=>100, + 'value2'=>200))); + $res=$this->db->findBy('unittest', 'value1', 100); + $this->assertEquals(1, count($res)); + } + public function testUpdate() + { + $this->assertTrue($this->db->save('unittest', array('value1'=>100, + 'value2'=>200, + 'id'=>1))); + $res=$this->db->findBy('unittest', 'value1', 100); + $this->assertTrue($this->db->update('unittest', 1, + array('value2'=>1000))); + + $res=$this->db->findBy('unittest', 'id', 1, 1); + $this->assertEquals(1000, $res['value2']); + } } ?> \ No newline at end of file diff --git a/tests/syncLibTest.php b/tests/syncLibTest.php index 323f828..55452c6 100644 --- a/tests/syncLibTest.php +++ b/tests/syncLibTest.php @@ -27,7 +27,7 @@ class SyncLibTest extends PHPUnit_Framework_TestCase { $sl = new SyncLib(); $this->assertGreaterThan(1, $sl->getNumberOfServers()); - $this->assertEquals($sl->getServer(0), "http://api2.yubico.com/wsapi/sync"); + $this->assertEquals($sl->getServer(0), "http://1.2.3.4/wsapi/2.0/sync"); } @@ -40,14 +40,14 @@ class SyncLibTest extends PHPUnit_Framework_TestCase $sl->queue(array('modified'=>1259585588, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>10, 'yk_use'=>20, 'yk_high'=>100, 'yk_low'=>1000), array('modified'=>1259585588, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>10, 'yk_use'=>18, 'yk_high'=>100, @@ -59,7 +59,7 @@ class SyncLibTest extends PHPUnit_Framework_TestCase $lastSync=$sl->getLast(); $this->assertEquals($lastSync['modified'], 1259585588); $this->assertEquals($lastSync['otp'], "ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui"); - $this->assertEquals($lastSync['yk_identity'], "cccccccccccc"); + $this->assertEquals($lastSync['yk_publicname'], "cccccccccccc"); $this->assertEquals($lastSync['yk_counter'], 10); $this->assertEquals($lastSync['yk_use'], 20); $this->assertEquals($lastSync['yk_high'], 100); @@ -135,14 +135,14 @@ class SyncLibTest extends PHPUnit_Framework_TestCase $this->assertTrue( $sl->queue(array('modified'=>1259585588+1000, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>9, 'yk_use'=>3, 'yk_high'=>100, 'yk_low'=>1000), array('modified'=>1259585588, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>10, 'yk_use'=>18, 'yk_high'=>100, @@ -159,14 +159,14 @@ class SyncLibTest extends PHPUnit_Framework_TestCase $this->assertTrue( $sl->queue(array('modified'=>1259585588+1000, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>9, 'yk_use'=>3, 'yk_high'=>100, 'yk_low'=>1000), array('modified'=>1259585588, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>10, 'yk_use'=>18, 'yk_high'=>100, @@ -193,14 +193,14 @@ class SyncLibTest extends PHPUnit_Framework_TestCase $this->assertTrue( $sl->queue(array('modified'=>1259585588+1000, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>9, 'yk_use'=>3, 'yk_high'=>100, 'yk_low'=>1000), array('modified'=>1259585588, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>10, 'yk_use'=>18, 'yk_high'=>100, @@ -227,14 +227,14 @@ class SyncLibTest extends PHPUnit_Framework_TestCase $this->assertTrue( $sl->queue(array('modified'=>1259585588+1000, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>9, 'yk_use'=>3, 'yk_high'=>100, 'yk_low'=>1000), array('modified'=>1259585588, 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", - 'yk_identity'=>"cccccccccccc", + 'yk_publicname'=>"cccccccccccc", 'yk_counter'=>10, 'yk_use'=>18, 'yk_high'=>100, @@ -250,8 +250,34 @@ class SyncLibTest extends PHPUnit_Framework_TestCase } - public function testActivateQueue() + public function testNullQueue() { + $sl = new SyncLib(); + $sl->syncServers = array("http://localhost/wsapi/syncvalid1", + "http://doesntexist/wsapi/syncvalid2", + "http://localhost/wsapi/syncvalid3"); + + $start_length=$sl->getQueueLength(); + $p1=array('modified'=>1259585588+1000, + 'otp'=>"ccccccccccccfrhiutjgfnvgdurgliidceuilikvfhui", + 'yk_publicname'=>"cccccccccccc", + 'yk_counter'=>9, + 'yk_use'=>3, + 'yk_high'=>100, + 'yk_low'=>1000); + + $this->assertTrue($sl->queue($p1, $p1)); + + $res=$sl->getLast(); + $this->assertNotNull($res['queued']); + $res=$sl->sync(3); + + $this->assertEquals(1+$start_length, $sl->getQueueLength()); + $res=$sl->getLast(); + $this->assertNull($res['queued']); + + } + } ?> \ No newline at end of file diff --git a/ykval-daemon b/ykval-daemon index 4969830..a8c3305 100755 --- a/ykval-daemon +++ b/ykval-daemon @@ -21,15 +21,29 @@ if ($path){ } error_log($appname . " started"); -$sl = new SyncLib(); +$servers=explode(";", $baseParams['__YKVAL_SYNC_POOL__']); +$resources=array(); +$descriptors=array(); +$pipes=array(); +$execstring="php -d error_log='/var/log/apache2/error.log' -f ./app1.php "; +foreach($servers as $server) { + $resources[$server]=proc_open($execstring . $server, $descriptors, $pipes); +} # Loop forever and resync while (True) { - $sl->reSync($baseParams['__YKVAL_SYNC_OLD_LIMIT__']); - - sleep($baseParams['__YKVAL_SYNC_INTERVAL__']); + foreach($resources as $server=>$resource) { + $res=proc_get_status($resource); + if ($res['running']==True){ + System_Daemon::log(System_Daemon::LOG_INFO, "sync server for " . $server . " status=running"); + } else { + System_Daemon::log(System_Daemon::LOG_INFO, "sync server for " . $server . " not running. Trying to restart."); + $resources[$server]=proc_open($execstring . $server, $descriptors, $pipes); + } + } + sleep(60); } - + System_Daemon::stop(); ?> diff --git a/ykval-db.php b/ykval-db.php index b16ec64..9810e05 100644 --- a/ykval-db.php +++ b/ykval-db.php @@ -137,6 +137,39 @@ class Db mysql_query("TRUNCATE TABLE " . $name); } + /** + * function to update row in database by a where condition + * + * @param string $table Database table to update row in + * @param int $id Id on row to update + * @param array $values Array with key=>values to update + * @return boolean True on success, otherwise false. + * + */ + public function updateBy($table, $k, $v, $values) + { + + foreach ($values as $key=>$value){ + if ($value != null) $query .= ' ' . $key . "='" . $value . "',"; + else $query .= ' ' . $key . '=NULL,'; + } + if (! $query) { + log("no values to set in query. Not updating DB"); + return true; + } + + $query = rtrim($query, ",") . " WHERE " . $k . ' = ' . $v; + // Insert UPDATE statement at beginning + $query = "UPDATE " . $table . " SET " . $query; + if (! mysql_query($query)){ + error_log('Query failed: ' . mysql_error()); + error_log('Query was: ' . $query); + return false; + } + return true; + } + + /** * function to update row in database * @@ -148,25 +181,9 @@ class Db */ public function update($table, $id, $values) { - - foreach ($values as $key=>$value){ - if ($value != null) $query = $query . " " . $key . "='" . $value . "',"; - } - if (! $query) { - log("no values to set in query. Not updating DB"); - return true; - } - - $query = rtrim($query, ",") . " WHERE id = " . $id; - // Insert UPDATE statement at beginning - $query = "UPDATE " . $table . " SET " . $query; - if (! mysql_query($query)){ - error_log('Query failed: ' . mysql_error()); - error_log('Query was: ' . $query); - return false; - } - return true; + return $this->updateBy($table, 'id', $id, $values); } + /** * function to update row in database * @@ -254,28 +271,7 @@ or false on failure. */ public function findBy($table, $key, $value, $nr=null, $rev=null) { - $query="SELECT * FROM " . $table; - if ($key!=null) $query.= " WHERE " . $key . " = '" . $value . "'"; - if ($rev==1) $query.= " ORDER BY id DESC"; - if ($nr!=null) $query.= " LIMIT " . $nr; - $result = mysql_query($query); - if (! $result) { - error_log('Query failed: ' . mysql_error()); - error_log('Query was: ' . $query); - return false; - } - if ($nr==1) { - $row = mysql_fetch_array($result, MYSQL_ASSOC); - return $row; - } - else { - $collection=array(); - while($row = mysql_fetch_array($result, MYSQL_ASSOC)){ - $collection[]=$row; - } - return $collection; - } - + return $this->findByMultiple($table, array($key=>$value), $nr, $rev); } /** @@ -299,15 +295,19 @@ or false on failure. } $query.= " FROM " . $table; if ($where!=null){ - $query.= " WHERE"; foreach ($where as $key=>$value) { - $query.= " ". $key . " = '" . $value . "' and"; + if ($key!= Null) { + if ($value != Null) $match.= " ". $key . " = '" . $value . "' and"; + else $match.= " ". $key . " is NULL and"; + } } + if ($match!=null) $query .= " WHERE" . $match; $query=rtrim($query, "and"); $query=rtrim($query); } if ($rev==1) $query.= " ORDER BY id DESC"; if ($nr!=null) $query.= " LIMIT " . $nr; + // error_log('query is ' .$query); $result = mysql_query($query); if (! $result) { error_log('Query failed: ' . mysql_error()); @@ -365,6 +365,7 @@ or false on failure. public function customQuery($query) { + error_log("custom query: " . $query); return mysql_query($query); } /** diff --git a/ykval-db.sql b/ykval-db.sql index acc0e76..50c61b2 100644 --- a/ykval-db.sql +++ b/ykval-db.sql @@ -1,7 +1,7 @@ CREATE TABLE clients ( id INT NOT NULL AUTO_INCREMENT, active BOOLEAN DEFAULT TRUE, - created DATETIME NOT NULL, + created INT NOT NULL, secret VARCHAR(60) NOT NULL DEFAULT '', email VARCHAR(255), notes VARCHAR(100) DEFAULT '', @@ -12,23 +12,23 @@ CREATE TABLE clients ( CREATE TABLE yubikeys ( id INT NOT NULL UNIQUE AUTO_INCREMENT, active BOOLEAN DEFAULT TRUE, - created DATETIME NOT NULL, - accessed DATETIME, - publicName VARCHAR(16) UNIQUE NOT NULL COLLATE ascii_bin, - internalName VARCHAR(12) NOT NULL COLLATE ascii_bin, - counter INT, - low INT, - high INT, - sessionUse INT, - nonce VARCHAR(64) DEFAULT '', + created INT NOT NULL, + modified INT NOT NULL, + yk_publicname VARCHAR(16) UNIQUE NOT NULL COLLATE ascii_bin, + yk_internalname VARCHAR(12) NOT NULL COLLATE ascii_bin, + yk_counter INT NOT NULL, + yk_use INT NOT NULL, + yk_low INT, + yk_high INT, + nonce VARCHAR(32) DEFAULT '', notes VARCHAR(100) DEFAULT '', PRIMARY KEY (id) ); CREATE TABLE queue ( id INT NOT NULL UNIQUE AUTO_INCREMENT, - queued_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - modified_time TIMESTAMP, + queued INT DEFAULT NULL, + modified INT DEFAULT NULL, random_key INT, otp VARCHAR(100) NOT NULL, server VARCHAR(100) NOT NULL, diff --git a/ykval-queuedaemon.php b/ykval-queuedaemon.php index 7cd77d9..01fda98 100644 --- a/ykval-queuedaemon.php +++ b/ykval-queuedaemon.php @@ -3,13 +3,19 @@ require_once 'ykval-synclib.php'; require_once 'ykval-config.php'; +if ($argc==2) $server=$argv[1]; + else { + echo "Usage: " . $argv[0] . " server\n"; + exit; + } + $sl = new SyncLib(); $resync = $baseParams['__YKVAL_SYNC_INTERVAL__']; # Loop forever and resync while (True) { - $sl->reSync($baseParams['__YKVAL_SYNC_OLD_LIMIT__']); + $sl->reSync($baseParams['__YKVAL_SYNC_OLD_LIMIT__'], 10); sleep($baseParams['__YKVAL_SYNC_INTERVAL__']); } diff --git a/ykval-sync.php b/ykval-sync.php index ffef789..69dc170 100644 --- a/ykval-sync.php +++ b/ykval-sync.php @@ -22,7 +22,7 @@ if (! $sync->isConnected()) { $syncParams=array('modified'=>Null, 'otp'=>Null, 'nonce'=>Null, - 'yk_identity'=>Null, + 'yk_publicname'=>Null, 'yk_counter'=>Null, 'yk_use'=>Null, 'yk_high'=>Null, @@ -49,16 +49,16 @@ debug($tmp_log); # Get local counter data # -$yk_identity = $syncParams['yk_identity']; -$localParams = $sync->getLocalParams($yk_identity); +$yk_publicname = $syncParams['yk_publicname']; +$localParams = $sync->getLocalParams($yk_publicname); if (!$localParams) { - debug('Invalid Yubikey ' . $yk_identity); + debug('Invalid Yubikey ' . $yk_publicname); sendResp(S_BACKEND_ERROR, $apiKey); exit; } if ($localParams['active'] != 1) { - debug('De-activated Yubikey ' . $yk_identity); + debug('De-activated Yubikey ' . $yk_publicname); sendResp(S_BAD_OTP, $apiKey); exit; } @@ -100,7 +100,7 @@ if ($sync->countersEqual($localParams, $syncParams)) { $extra=array('modified'=>$localParams['modified'], 'nonce'=>$localParams['nonce'], - 'yk_identity'=>$yk_identity, + 'yk_publicname'=>$yk_publicname, 'yk_counter'=>$localParams['yk_counter'], 'yk_use'=>$localParams['yk_use'], 'yk_high'=>$localParams['yk_high'], diff --git a/ykval-synclib.php b/ykval-synclib.php index 3abe4ca..99207cb 100644 --- a/ykval-synclib.php +++ b/ykval-synclib.php @@ -45,7 +45,6 @@ class SyncLib if (isset($this->syncServers[$index])) return $this->syncServers[$index]; else return ""; } - function getClientData($client) { $res=$this->db->customQuery('SELECT id, secret FROM clients WHERE active AND id='.mysql_quote($client)); @@ -59,11 +58,12 @@ class SyncLib { $res=$this->db->last('queue', 1); $info=$this->otpParamsFromInfoString($res['info']); - return array('modified'=>$this->DbTimeToUnix($res['modified_time']), + return array('queued'=>$res['queued'], + 'modified'=>$res['modified'], 'otp'=>$res['otp'], 'server'=>$res['server'], 'nonce'=>$info['nonce'], - 'yk_identity'=>$info['yk_identity'], + 'yk_publicname'=>$info['yk_publicname'], 'yk_counter'=>$info['yk_counter'], 'yk_use'=>$info['yk_use'], 'yk_high'=>$info['yk_high'], @@ -71,12 +71,12 @@ class SyncLib } public function getQueueLength() { - return count($this->db->last('queue', NULL)); + return count($this->db->last('queue', null)); } public function createInfoString($otpParams, $localParams) { - return 'yk_identity=' . $otpParams['yk_identity'] . + return 'yk_publicname=' . $otpParams['yk_publicname'] . '&yk_counter=' . $otpParams['yk_counter'] . '&yk_use=' . $otpParams['yk_use'] . '&yk_high=' . $otpParams['yk_high'] . @@ -108,11 +108,12 @@ class SyncLib $this->otpParams = $otpParams; $this->localParams = $localParams; - + $queued=time(); $res=True; foreach ($this->syncServers as $server) { - if(! $this->db->save('queue', array('modified_time'=>$this->UnixToDbTime($otpParams['modified']), + if(! $this->db->save('queue', array('queued'=>$queued, + 'modified'=>$otpParams['modified'], 'otp'=>$otpParams['otp'], 'server'=>$server, 'random_key'=>$this->random_key, @@ -131,54 +132,43 @@ class SyncLib $logMsg=$this->logname . ':' . $level . ':' . $msg; if ($params) $logMsg .= ' modified=' . $params['modified'] . ' nonce=' . $params['nonce'] . - ' yk_identity=' . $params['yk_identity'] . + ' yk_publicname=' . $params['yk_publicname'] . ' yk_counter=' . $params['yk_counter'] . ' yk_use=' . $params['yk_use'] . ' yk_high=' . $params['yk_high'] . ' yk_low=' . $params['yk_low']; error_log($logMsg); } - function updateLocalParams($id,$params) + function getLocalParams($yk_publicname) { - return $this->db->update('yubikeys', - $id, - array('accessed'=>UnixToDbTime($params['modified']), - 'nonce'=>$params['nonce'], - 'counter'=>$params['yk_counter'], - 'sessionUse'=>$params['yk_use'], - 'high'=>$params['yk_high'], - 'low'=>$params['yk_low'])); - } - function getLocalParams($yk_identity) - { - $this->log("notice", "searching for " . $yk_identity . " (" . modhex2b64($yk_identity) . ") in local db"); - $res = $this->db->findBy('yubikeys', 'publicName', modhex2b64($yk_identity),1); + $this->log("notice", "searching for " . $yk_publicname . " (" . $yk_publicname . ") in local db"); + $res = $this->db->findBy('yubikeys', 'yk_publicname', $yk_publicname,1); if (!$res) { - $this->log('notice', 'Discovered new identity ' . $yk_identity); - $this->db->save('yubikeys', array('publicName'=>modhex2b64($yk_identity), + $this->log('notice', 'Discovered new identity ' . $yk_publicname); + $this->db->save('yubikeys', array('yk_publicname'=>$yk_publicname, 'active'=>1, - 'counter'=>0, - 'sessionUse'=>0, + 'yk_counter'=>0, + 'yk_use'=>0, 'nonce'=>0)); - $res=$this->db->findBy('yubikeys', 'publicName', modhex2b64($yk_identity), 1); + $res=$this->db->findBy('yubikeys', 'yk_publicname', $yk_publicname, 1); } if ($res) { $localParams=array('id'=>$res['id'], - 'modified'=>$this->DbTimeToUnix($res['accessed']), + 'modified'=>$res['modified'], 'otp'=>$res['otp'], 'nonce'=>$res['nonce'], 'active'=>$res['active'], - 'yk_identity'=>$yk_identity, - 'yk_counter'=>$res['counter'], - 'yk_use'=>$res['sessionUse'], - 'yk_high'=>$res['high'], - 'yk_low'=>$res['low']); + 'yk_publicname'=>$yk_publicname, + 'yk_counter'=>$res['yk_counter'], + 'yk_use'=>$res['yk_use'], + 'yk_high'=>$res['yk_high'], + 'yk_low'=>$res['yk_low']); $this->log("notice", "counter found in db ", $localParams); return $localParams; } else { - $this->log('notice', 'params for identity ' . $yk_identity . ' not found in database'); + $this->log('notice', 'params for identity ' . $yk_publicname . ' not found in database'); return false; } } @@ -187,8 +177,8 @@ class SyncLib { preg_match("/^modified=([0-9]*)/m", $str, $out); $resParams['modified']=$out[1]; - preg_match("/^yk_identity=([[:alpha:]]*)/m", $str, $out); - $resParams['yk_identity']=$out[1]; + preg_match("/^yk_publicname=([[:alpha:]]*)/m", $str, $out); + $resParams['yk_publicname']=$out[1]; preg_match("/^yk_counter=([0-9]*)/m", $str, $out); $resParams['yk_counter']=$out[1]; preg_match("/^yk_use=([0-9]*)/m", $str, $out); @@ -205,17 +195,17 @@ class SyncLib public function updateDbCounters($params) { - $res=$this->db->lastBy('yubikeys', 'publicName', modhex2b64($params['yk_identity'])); + $res=$this->db->lastBy('yubikeys', 'yk_publicname', $params['yk_publicname']); if (isset($res['id'])) { - $condition='('.$params['yk_counter'].'>counter or ('.$params['yk_counter'].'=counter and ' . - $params['yk_use'] . '>sessionUse))' ; + $condition='('.$params['yk_counter'].'>yk_counter or ('.$params['yk_counter'].'=yk_counter and ' . + $params['yk_use'] . '>yk_use))' ; if(! $this->db->conditional_update('yubikeys', $res['id'], - array('accessed'=>$this->UnixToDbTime($params['modified']), - 'counter'=>$params['yk_counter'], - 'sessionUse'=>$params['yk_use'], - 'low'=>$params['yk_low'], - 'high'=>$params['yk_high'], + 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']), $condition)) { @@ -254,14 +244,22 @@ class SyncLib preg_match('/url=(.*)\?/', $answer, $out); $server=$out[1]; debug("server=" . $server); - $this->db->deleteByMultiple('queue', array("modified_time"=>$this->UnixToDbTime($this->otpParams['modified']), "random_key"=>$this->random_key, 'server'=>$server)); + $this->db->deleteByMultiple('queue', + array("modified"=>$this->otpParams['modified'], + "random_key"=>$this->random_key, + 'server'=>$server)); } - public function reSync($older_than=10) + public function reSync($older_than=10, $timeout) { + /* Loop over all unique servers in queue */ + $res=$this->db->customQuery("select distinct server from queue WHERE (queued_time < DATE_SUB(now(), INTERVAL " . $older_than . " MINUTE) or queued_time is null)"); + error_log("found " . mysql_num_rows($res) . " unique servers"); + return true; + $urls=array(); # TODO: move statement to DB class, this looks grotesque - $res=$this->db->customQuery("select * from queue WHERE queued_time < DATE_SUB(now(), INTERVAL " . $older_than . " MINUTE)"); + $res=$this->db->customQuery("select * from queue WHERE (queued_time < DATE_SUB(now(), INTERVAL " . $older_than . " MINUTE) or queued_time is null) and server='" . $server . "'"); $this->log('notice', "found " . mysql_num_rows($res) . " old queue entries"); $collection=array(); while($row = mysql_fetch_array($res, MYSQL_ASSOC)) { @@ -272,27 +270,32 @@ class SyncLib $urls[]=$row['server'] . "?otp=" . $row['otp'] . - "&modified=" . $this->DbTimeToUnix($row['modified_time']) . + "&modified=" . $row['modified'] . "&" . $this->otpPartFromInfoString($row['info']); } - /* We do not want to sent out to many requests at once since this - tends to be very slow since most system have limits on number - of outgoing connections */ - $url_chunks=array_chunk($urls, $this->max_url_chunk); - foreach($url_chunks as $urls) { + /* Send out until no URL's left, or a timeout */ + + foreach($urls as $url) { - $ans_arr=$this->retrieveURLasync($urls, count($urls), $this->resync_timeout); - - if (!is_array($ans_arr)) { - $this->log('notice', 'No responses from validation server pool'); - $ans_arr=array(); + $ch = curl_init($this->url); + curl_setopt($ch, CURLOPT_USERAGENT, "YK-VAL"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_FAILONERROR, true); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + $response = curl_exec($ch); + curl_close($ch); + + if ($response==False) { + $this->log('warning', 'Timeout. Stopping queue resync at the moment'); + return false; } - - foreach ($ans_arr as $answer){ - /* Parse out parameters from each response */ - $resParams=$this->parseParamsFromMultiLineString($answer); + + if (preg_match("/^OK/", $respone)) { + + $resParams=$this->parseParamsFromMultiLineString($response); $this->log("notice", "response contains ", $resParams); /* Update database counters */ @@ -336,7 +339,7 @@ class SyncLib $this->log("warning", "queued:Local server out of sync, local counters ", $localParams); $this->log("warning", "queued:Local server out of sync, remote counters ", $resParams); } - + if ($this->countersHigherThan($resParams, $otpParams) || ($this->countersEqual($resParams, $otpParams) && $resParams['nonce']!=$otpParams['nonce'])) { @@ -344,7 +347,7 @@ class SyncLib /* If received sync response have higher counters than OTP or same counters with different nonce (indicating REPLAYED_OTP) */ - + $this->log("warning", "queued:replayed OTP, remote counters " , $resParams); $this->log("warning", "queued:replayed OTP, otp counters", $otpParams); } @@ -355,6 +358,7 @@ class SyncLib } } } + return true; } public function sync($ans_req, $timeout=1) { @@ -363,11 +367,11 @@ class SyncLib */ $urls=array(); - $res=$this->db->findByMultiple('queue', array("modified_time"=>$this->UnixToDbTime($this->otpParams['modified']), "random_key"=>$this->random_key)); + $res=$this->db->findByMultiple('queue', array("modified"=>$this->otpParams['modified'], "random_key"=>$this->random_key)); foreach ($res as $row) { $urls[]=$row['server'] . "?otp=" . $row['otp'] . - "&modified=" . $this->DbTimeToUnix($row['modified_time']) . + "&modified=" . $row['modified'] . "&" . $this->otpPartFromInfoString($row['info']); } @@ -443,6 +447,15 @@ class SyncLib } + /* + NULL queued_time for remaining entries in queue, to allow + daemon to take care of them as soon as possible. */ + + $this->db->updateBy('queue', 'random_key', $this->random_key, + 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. diff --git a/ykval-verify.php b/ykval-verify.php index 352f08f..5e6578e 100644 --- a/ykval-verify.php +++ b/ykval-verify.php @@ -9,6 +9,7 @@ header("content-type: text/plain"); debug("Request: " . $_SERVER['QUERY_STRING']); +/* Detect protocol version */ if (preg_match("/\/wsapi\/([0-9]*)\.([0-9]*)\//", $_SERVER['REQUEST_URI'], $out)) { $protocol_version=$out[1]+$out[2]*0.1; } else { @@ -123,10 +124,10 @@ debug("Decrypted OTP:", $otpinfo); //// Get Yubikey from DB // $devId = substr($otp, 0, strlen ($otp) - TOKEN_LEN); -$yk_identity=$devId; -$localParams = $sync->getLocalParams($yk_identity); +$yk_publicname=$devId; +$localParams = $sync->getLocalParams($yk_publicname); if (!$localParams) { - debug('Invalid Yubikey ' . $yk_identity); + debug('Invalid Yubikey ' . $yk_publicname); sendResp(S_BACKEND_ERROR, $apiKey); exit; } @@ -143,7 +144,7 @@ if ($localParams['active'] != 1) { $otpParams=array('modified'=>time(), 'otp'=>$otp, 'nonce'=>$nonce, - 'yk_identity'=>$devId, + 'yk_publicname'=>$devId, 'yk_counter'=>$otpinfo['session_counter'], 'yk_use'=>$otpinfo['session_use'], 'yk_high'=>$otpinfo['high'],