2009-12-02 18:32:20 +01:00
< ? php
require_once 'ykval-config.php' ;
require_once 'ykval-common.php' ;
2009-12-15 16:39:47 +01:00
require_once 'ykval-db.php' ;
2010-01-11 13:06:00 +01:00
require_once 'ykval-log.php' ;
2009-12-02 18:32:20 +01:00
class SyncLib
{
public $syncServers = null ;
public $dbConn = null ;
2009-12-15 11:17:51 +01:00
function __construct ( $logname = 'ykval-synclib' )
2009-12-02 18:32:20 +01:00
{
2010-01-11 13:06:00 +01:00
$this -> myLog = new Log ( $logname );
2009-12-02 18:32:20 +01:00
global $baseParams ;
2010-01-08 17:35:25 +01:00
$this -> syncServers = $baseParams [ '__YKVAL_SYNC_POOL__' ];
2012-06-12 13:27:51 +02:00
$this -> db = Db :: GetDatabaseHandle ( $baseParams , $logname );
2009-12-15 11:17:51 +01:00
$this -> isConnected = $this -> db -> connect ();
2012-05-29 11:07:19 +02:00
$this -> server_nonce = md5 ( uniqid ( rand ()));
2010-01-12 14:00:28 +01:00
2009-12-02 18:32:20 +01:00
}
2010-01-14 12:58:19 +01:00
function addField ( $name , $value )
{
$this -> myLog -> addField ( $name , $value );
$this -> db -> addField ( $name , $value );
}
2010-02-22 14:01:49 +01:00
2012-05-29 11:07:19 +02:00
function isConnected ()
2009-12-15 11:17:51 +01:00
{
return $this -> isConnected ;
}
2010-02-22 14:01:49 +01:00
2009-12-02 18:32:20 +01:00
function DbTimeToUnix ( $db_time )
{
$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 );
}
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
function UnixToDbTime ( $unix )
{
return date ( 'Y-m-d H:i:s' , $unix );
2012-05-29 11:07:19 +02:00
}
2010-02-22 14:01:49 +01:00
2009-12-02 18:32:20 +01:00
function getServer ( $index )
{
if ( isset ( $this -> syncServers [ $index ])) return $this -> syncServers [ $index ];
else return " " ;
}
2010-02-22 14:01:49 +01:00
2009-12-15 11:17:51 +01:00
function getClientData ( $client )
{
2012-06-12 10:35:49 +02:00
$res = $this -> db -> customQuery ( " SELECT id, secret FROM clients WHERE active='1' AND id=' " . $client . " ' " );
$r = $this -> db -> fetchArray ( $res );
$this -> db -> closeCursor ( $res );
2010-05-17 15:20:49 +02:00
if ( $r ) return $r ;
2010-01-08 17:35:25 +01:00
else return false ;
2009-12-15 11:17:51 +01:00
}
2010-02-22 14:01:49 +01:00
2009-12-02 18:32:20 +01:00
public function getQueueLength ()
{
2010-01-12 14:00:28 +01:00
return count ( $this -> db -> findBy ( 'queue' , null , null , null ));
2009-12-02 18:32:20 +01:00
}
2009-12-07 14:33:24 +01:00
public function createInfoString ( $otpParams , $localParams )
2009-12-02 18:32:20 +01:00
{
2010-01-08 14:54:33 +01:00
return 'yk_publicname=' . $otpParams [ 'yk_publicname' ] .
2009-12-04 12:57:49 +01:00
'&yk_counter=' . $otpParams [ 'yk_counter' ] .
'&yk_use=' . $otpParams [ 'yk_use' ] .
'&yk_high=' . $otpParams [ 'yk_high' ] .
2009-12-07 14:33:24 +01:00
'&yk_low=' . $otpParams [ 'yk_low' ] .
2009-12-15 11:17:51 +01:00
'&nonce=' . $otpParams [ 'nonce' ] .
2009-12-07 14:33:24 +01:00
',local_counter=' . $localParams [ 'yk_counter' ] .
'&local_use=' . $localParams [ 'yk_use' ];
}
2010-02-22 14:01:49 +01:00
2009-12-07 17:10:07 +01:00
public function otpParamsFromInfoString ( $info ) {
$out = explode ( " , " , $info );
parse_str ( $out [ 0 ], $params );
return $params ;
}
2010-02-22 14:01:49 +01:00
2009-12-07 14:33:24 +01:00
public function otpPartFromInfoString ( $info ) {
$out = explode ( " , " , $info );
return $out [ 0 ];
}
2010-02-22 14:01:49 +01:00
2012-05-29 11:07:19 +02:00
public function localParamsFromInfoString ( $info )
2009-12-07 14:33:24 +01:00
{
$out = explode ( " , " , $info );
2009-12-07 17:10:07 +01:00
parse_str ( $out [ 1 ], $params );
2012-05-29 11:07:19 +02:00
return array ( 'yk_counter' => $params [ 'local_counter' ],
2009-12-07 17:10:07 +01:00
'yk_use' => $params [ 'local_use' ]);
2009-12-07 14:33:24 +01:00
}
2010-02-22 14:01:49 +01:00
2009-12-07 14:33:24 +01:00
public function queue ( $otpParams , $localParams )
{
$info = $this -> createInfoString ( $otpParams , $localParams );
2009-12-04 12:57:49 +01:00
$this -> otpParams = $otpParams ;
$this -> localParams = $localParams ;
2012-05-29 11:07:19 +02:00
2010-01-08 14:54:33 +01:00
$queued = time ();
2009-12-02 18:32:20 +01:00
$res = True ;
foreach ( $this -> syncServers as $server ) {
2012-05-29 11:07:19 +02:00
2010-01-08 14:54:33 +01:00
if ( ! $this -> db -> save ( 'queue' , array ( 'queued' => $queued ,
2012-05-29 11:07:19 +02:00
'modified' => $otpParams [ 'modified' ],
'otp' => $otpParams [ 'otp' ],
2009-12-02 18:32:20 +01:00
'server' => $server ,
2010-01-12 14:00:28 +01:00
'server_nonce' => $this -> server_nonce ,
2009-12-02 18:32:20 +01:00
'info' => $info ))) $res = False ;
}
return $res ;
}
2010-02-22 14:01:49 +01:00
2009-12-02 18:32:20 +01:00
public function getNumberOfServers ()
{
if ( is_array ( $this -> syncServers )) return count ( $this -> syncServers );
else return 0 ;
}
2010-01-11 13:06:00 +01:00
public function log ( $priority , $msg , $params = NULL )
2009-12-02 18:32:20 +01:00
{
2010-01-11 13:06:00 +01:00
$logMsg = $msg ;
2009-12-15 11:17:51 +01:00
if ( $params ) $logMsg .= ' modified=' . $params [ 'modified' ] .
' nonce=' . $params [ 'nonce' ] .
2010-01-08 14:54:33 +01:00
' yk_publicname=' . $params [ 'yk_publicname' ] .
2012-05-29 11:07:19 +02:00
' yk_counter=' . $params [ 'yk_counter' ] .
' yk_use=' . $params [ 'yk_use' ] .
' yk_high=' . $params [ 'yk_high' ] .
2009-12-15 11:17:51 +01:00
' yk_low=' . $params [ 'yk_low' ];
2010-01-11 13:06:00 +01:00
if ( $this -> myLog ) $this -> myLog -> log ( $priority , $logMsg );
else error_log ( " Warning: myLog uninitialized in ykval-synclib.php. Message is " . $logMsg );
2009-12-02 18:32:20 +01:00
}
2010-02-22 14:01:49 +01:00
2010-01-08 14:54:33 +01:00
function getLocalParams ( $yk_publicname )
2009-12-15 11:17:51 +01:00
{
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_INFO , " searching for yk_publicname " . $yk_publicname . " in local db " );
2012-06-12 10:35:49 +02:00
$res = $this -> db -> findBy ( 'yubikeys' , 'yk_publicname' , $yk_publicname , 1 );
2009-12-02 18:32:20 +01:00
2009-12-15 11:17:51 +01:00
if ( ! $res ) {
2010-01-11 13:06:00 +01:00
$this -> log ( LOG_NOTICE , 'Discovered new identity ' . $yk_publicname );
2012-05-29 11:07:19 +02:00
$this -> db -> save ( 'yubikeys' , array ( 'active' => 1 ,
2010-01-12 18:37:00 +01:00
'created' => time (),
2010-01-25 15:49:49 +01:00
'modified' =>- 1 ,
2010-01-12 18:37:00 +01:00
'yk_publicname' => $yk_publicname ,
2010-01-25 15:28:46 +01:00
'yk_counter' =>- 1 ,
'yk_use' =>- 1 ,
'yk_low' =>- 1 ,
'yk_high' =>- 1 ,
2010-01-25 16:09:15 +01:00
'nonce' => '0000000000000000' ,
2010-01-12 18:37:00 +01:00
'notes' => '' ));
2010-01-12 14:00:28 +01:00
$res = $this -> db -> findBy ( 'yubikeys' , 'yk_publicname' , $yk_publicname , 1 );
2009-12-15 11:17:51 +01:00
}
if ( $res ) {
2012-06-12 10:35:49 +02:00
$localParams = array ( 'modified' => $this -> db -> getRowValue ( $res , 'modified' ),
'nonce' => $this -> db -> getRowValue ( $res , 'nonce' ),
'active' => $this -> db -> getRowValue ( $res , 'active' ),
'yk_publicname' => $yk_publicname ,
'yk_counter' => $this -> db -> getRowValue ( $res , 'yk_counter' ),
'yk_use' => $this -> db -> getRowValue ( $res , 'yk_use' ),
'yk_high' => $this -> db -> getRowValue ( $res , 'yk_high' ),
'yk_low' => $this -> db -> getRowValue ( $res , 'yk_low' ));
2012-05-29 11:07:19 +02:00
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_INFO , " yubikey found in db " , $localParams );
2009-12-15 11:17:51 +01:00
return $localParams ;
} else {
2010-01-12 14:00:28 +01:00
$this -> log ( LOG_NOTICE , 'params for yk_publicname ' . $yk_publicname . ' not found in database' );
2009-12-15 11:17:51 +01:00
return false ;
}
2009-12-02 18:32:20 +01:00
}
private function parseParamsFromMultiLineString ( $str )
{
2010-01-25 15:49:49 +01:00
$i = preg_match ( " /^modified=(-1|[0-9]+)/m " , $str , $out );
2010-01-25 15:28:46 +01:00
if ( $i != 1 ) {
$this -> log ( LOG_ALERT , " cannot parse modified value: $str " );
}
2009-12-02 18:32:20 +01:00
$resParams [ 'modified' ] = $out [ 1 ];
2010-01-25 15:28:46 +01:00
$i = preg_match ( " /^yk_publicname=([cbdefghijklnrtuv]+)/m " , $str , $out );
if ( $i != 1 ) {
$this -> log ( LOG_ALERT , " cannot parse publicname value: $str " );
}
2010-01-08 14:54:33 +01:00
$resParams [ 'yk_publicname' ] = $out [ 1 ];
2010-01-25 15:28:46 +01:00
$i = preg_match ( " /^yk_counter=(-1|[0-9]+)/m " , $str , $out );
if ( $i != 1 ) {
$this -> log ( LOG_ALERT , " cannot parse counter value: $str " );
}
2009-12-02 18:32:20 +01:00
$resParams [ 'yk_counter' ] = $out [ 1 ];
2010-01-25 15:28:46 +01:00
$i = preg_match ( " /^yk_use=(-1|[0-9]+)/m " , $str , $out );
if ( $i != 1 ) {
$this -> log ( LOG_ALERT , " cannot parse use value: $str " );
}
2009-12-02 18:32:20 +01:00
$resParams [ 'yk_use' ] = $out [ 1 ];
2010-01-25 15:28:46 +01:00
preg_match ( " /^yk_high=(-1|[0-9]+)/m " , $str , $out );
if ( $i != 1 ) {
$this -> log ( LOG_ALERT , " cannot parse high value: $str " );
}
2009-12-02 18:32:20 +01:00
$resParams [ 'yk_high' ] = $out [ 1 ];
2010-01-25 15:28:46 +01:00
preg_match ( " /^yk_low=(-1|[0-9]+)/m " , $str , $out );
if ( $i != 1 ) {
$this -> log ( LOG_ALERT , " cannot parse low value: $str " );
}
2009-12-02 18:32:20 +01:00
$resParams [ 'yk_low' ] = $out [ 1 ];
2010-01-25 15:28:46 +01:00
preg_match ( " /^nonce=([[:alnum:]]+)/m " , $str , $out );
if ( $i != 1 ) {
$this -> log ( LOG_ALERT , " cannot parse counter value: $str " );
}
2009-12-15 11:17:51 +01:00
$resParams [ 'nonce' ] = $out [ 1 ];
2009-12-02 18:32:20 +01:00
return $resParams ;
}
public function updateDbCounters ( $params )
{
2010-01-14 13:15:26 +01:00
if ( isset ( $params [ 'yk_publicname' ])) {
2010-01-08 14:54:33 +01:00
$condition = '(' . $params [ 'yk_counter' ] . '>yk_counter or (' . $params [ 'yk_counter' ] . '=yk_counter and ' .
$params [ 'yk_use' ] . '>yk_use))' ;
2012-05-29 11:07:19 +02:00
if ( ! $this -> db -> conditionalUpdateBy ( 'yubikeys' , 'yk_publicname' , $params [ 'yk_publicname' ],
array ( 'modified' => $params [ 'modified' ],
'yk_counter' => $params [ 'yk_counter' ],
2010-01-12 14:00:28 +01:00
'yk_use' => $params [ 'yk_use' ],
'yk_low' => $params [ 'yk_low' ],
2012-05-29 11:07:19 +02:00
'yk_high' => $params [ 'yk_high' ],
'nonce' => $params [ 'nonce' ]),
2010-01-12 14:00:28 +01:00
$condition ))
2009-12-02 18:32:20 +01:00
{
2010-01-11 13:06:00 +01:00
$this -> log ( LOG_CRIT , 'failed to update internal DB with new counters' );
2009-12-02 18:32:20 +01:00
return false ;
2012-05-29 11:07:19 +02:00
} else
2010-01-12 14:00:28 +01:00
{
2010-01-14 10:39:48 +01:00
if ( $this -> db -> rowCount () > 0 ) $this -> log ( LOG_INFO , " updated database " , $params );
else $this -> log ( LOG_INFO , 'database not updated' , $params );
2010-01-12 14:00:28 +01:00
return true ;
}
2009-12-02 18:32:20 +01:00
} else return false ;
}
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
public function countersHigherThan ( $p1 , $p2 )
{
if ( $p1 [ 'yk_counter' ] > $p2 [ 'yk_counter' ] ||
( $p1 [ 'yk_counter' ] == $p2 [ 'yk_counter' ] &&
$p1 [ 'yk_use' ] > $p2 [ 'yk_use' ])) return true ;
else return false ;
}
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
public function countersHigherThanOrEqual ( $p1 , $p2 )
{
if ( $p1 [ 'yk_counter' ] > $p2 [ 'yk_counter' ] ||
( $p1 [ 'yk_counter' ] == $p2 [ 'yk_counter' ] &&
$p1 [ 'yk_use' ] >= $p2 [ 'yk_use' ])) return true ;
else return false ;
}
2010-02-22 14:01:49 +01:00
2009-12-15 11:17:51 +01:00
public function countersEqual ( $p1 , $p2 ) {
return ( $p1 [ 'yk_counter' ] == $p2 [ 'yk_counter' ]) && ( $p1 [ 'yk_use' ] == $p2 [ 'yk_use' ]);
}
2009-12-07 14:33:24 +01:00
2012-05-29 11:07:19 +02:00
public function deleteQueueEntry ( $answer )
2009-12-07 14:33:24 +01:00
{
preg_match ( '/url=(.*)\?/' , $answer , $out );
$server = $out [ 1 ];
2012-05-29 11:07:19 +02:00
$this -> log ( LOG_INFO , " deleting server= " . $server .
2010-01-11 13:06:00 +01:00
" modified= " . $this -> otpParams [ 'modified' ] .
2010-01-12 14:00:28 +01:00
" server_nonce= " . $this -> server_nonce );
2012-05-29 11:07:19 +02:00
$this -> db -> deleteByMultiple ( 'queue' ,
2010-01-08 14:54:33 +01:00
array ( " modified " => $this -> otpParams [ 'modified' ],
2012-05-29 11:07:19 +02:00
" server_nonce " => $this -> server_nonce ,
2010-01-08 14:54:33 +01:00
'server' => $server ));
2009-12-07 14:33:24 +01:00
}
2010-01-10 17:46:11 +01:00
public function reSync ( $older_than = 60 , $timeout )
2009-12-07 14:33:24 +01:00
{
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_INFO , 'starting resync' );
2010-01-08 14:54:33 +01:00
/* Loop over all unique servers in queue */
2010-01-10 17:46:11 +01:00
$queued_limit = time () - $older_than ;
2012-06-12 10:35:49 +02:00
$server_res = $this -> db -> customQuery ( " select distinct server from queue WHERE queued < " . $queued_limit . " or queued is null " );
2012-05-29 11:07:19 +02:00
2012-06-12 10:35:49 +02:00
while ( $my_server = $this -> db -> fetchArray ( $server_res )) {
$this -> log ( LOG_INFO , " Sending queue request to server on server " . $this -> db -> getRowValue ( $my_server , 'server' ));
$res = $this -> db -> customQuery ( " select * from queue WHERE (queued < " . $queued_limit . " or queued is null) and server=' " . $this -> db -> getRowValue ( $my_server , 'server' ) . " ' " );
$ch = curl_init ();
while ( $entry = $this -> db -> fetchArray ( $res )) {
$this -> log ( LOG_INFO , " server= " . $this -> db -> getRowValue ( $entry , 'server' ) . " , info= " . $this -> db -> getRowValue ( $entry , 'info' ));
$url = $this -> db -> getRowValue ( $entry , 'server' ) .
" ?otp= " . $this -> db -> getRowValue ( $entry , 'otp' ) .
" &modified= " . $this -> db -> getRowValue ( $entry , 'modified' ) .
" & " . $this -> otpPartFromInfoString ( $this -> db -> getRowValue ( $entry , 'info' ));
2012-05-29 11:07:19 +02:00
2010-01-10 17:46:11 +01:00
/* Send out sync request */
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_DEBUG , 'url is ' . $url );
2012-06-11 12:41:50 +02:00
curl_setopt ( $ch , CURLOPT_URL , $url );
2010-01-10 17:46:11 +01:00
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 );
2012-05-29 11:07:19 +02:00
2010-01-10 17:46:11 +01:00
if ( $response == False ) {
2012-06-12 10:35:49 +02:00
$this -> log ( LOG_NOTICE , 'Timeout. Stopping queue resync for server ' . $this -> db -> getRowValue ( $entry , 'server' ));
2010-01-10 17:46:11 +01:00
break ;
}
2012-05-29 11:07:19 +02:00
2010-01-10 17:46:11 +01:00
if ( preg_match ( " /status=OK/ " , $response )) {
$resParams = $this -> parseParamsFromMultiLineString ( $response );
2010-01-13 13:32:38 +01:00
$this -> log ( LOG_DEBUG , " response contains " , $resParams );
2012-05-29 11:07:19 +02:00
2010-01-10 17:46:11 +01:00
/* Update database counters */
$this -> updateDbCounters ( $resParams );
2012-05-29 11:07:19 +02:00
2010-01-10 17:46:11 +01:00
/* Retrieve info from entry info string */
2012-05-29 11:07:19 +02:00
2012-06-12 10:35:49 +02:00
$validationParams = $this -> localParamsFromInfoString ( $this -> db -> getRowValue ( $entry , 'info' ));
$otpParams = $this -> otpParamsFromInfoString ( $this -> db -> getRowValue ( $entry , 'info' ));
2010-01-14 10:39:48 +01:00
$localParams = $this -> getLocalParams ( $otpParams [ 'yk_publicname' ]);
$this -> log ( LOG_DEBUG , " validation params: " , $validationParams );
$this -> log ( LOG_DEBUG , " OTP params: " , $otpParams );
2012-05-29 11:07:19 +02:00
/* Check for warnings */
2010-01-14 10:39:48 +01:00
if ( $this -> countersHigherThan ( $validationParams , $resParams )) {
$this -> log ( LOG_NOTICE , " Remote server out of sync compared to counters at validation request time. " );
}
2012-05-29 11:07:19 +02:00
2010-01-14 10:39:48 +01:00
if ( $this -> countersHigherThan ( $resParams , $validationParams )) {
$this -> log ( LOG_NOTICE , " Local server out of sync compared to counters at validation request time. " );
}
2012-05-29 11:07:19 +02:00
2009-12-07 14:33:24 +01:00
if ( $this -> countersHigherThan ( $localParams , $resParams )) {
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_WARNING , " Remote server out of sync compared to current local counters. " );
2009-12-07 14:33:24 +01:00
}
2012-05-29 11:07:19 +02:00
2009-12-07 14:33:24 +01:00
if ( $this -> countersHigherThan ( $resParams , $localParams )) {
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_WARNING , " Local server out of sync compared to current local counters. Local server updated. " );
2009-12-07 14:33:24 +01:00
}
2012-05-29 11:07:19 +02:00
2010-01-14 10:39:48 +01:00
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. " );
2012-05-29 11:07:19 +02:00
}
2010-01-14 10:39:48 +01:00
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. " );
}
2012-05-29 11:07:19 +02:00
2009-12-07 14:33:24 +01:00
/* Deletion */
2012-06-12 10:35:49 +02:00
$this -> log ( LOG_INFO , 'deleting queue entry with modified=' . $this -> db -> getRowValue ( $entry , 'modified' ) .
' server_nonce=' . $this -> db -> getRowValue ( $entry , 'server_nonce' ) .
' server=' . $this -> db -> getRowValue ( $entry , 'server' ));
2012-05-29 11:07:19 +02:00
$this -> db -> deleteByMultiple ( 'queue' ,
2012-06-12 10:35:49 +02:00
array ( " modified " => $this -> db -> getRowValue ( $entry , 'modified' ),
" server_nonce " => $this -> db -> getRowValue ( $entry , 'server_nonce' ),
'server' => $this -> db -> getRowValue ( $entry , 'server' )));
2012-05-29 11:11:56 +02:00
} else {
$this -> log ( LOG_ERR , " Remote server refused our sync request. Check remote server logs. " );
2009-12-07 14:33:24 +01:00
}
2012-05-29 11:07:19 +02:00
2010-01-10 17:46:11 +01:00
} /* End of loop over each queue entry for a server */
2012-06-12 10:35:49 +02:00
curl_close ( $ch );
$this -> db -> closeCursor ( $res );
2010-01-10 17:46:11 +01:00
} /* End of loop over each distinct server in queue */
2012-06-12 10:35:49 +02:00
$this -> db -> closeCursor ( $server_res );
2010-01-08 14:54:33 +01:00
return true ;
2009-12-07 14:33:24 +01:00
}
2012-05-29 11:07:19 +02:00
public function sync ( $ans_req , $timeout = 1 )
2009-12-02 18:32:20 +01:00
{
2009-12-04 11:58:37 +01:00
/*
Construct URLs
*/
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
$urls = array ();
2010-01-12 14:00:28 +01:00
$res = $this -> db -> findByMultiple ( 'queue' , array ( " modified " => $this -> otpParams [ 'modified' ], " server_nonce " => $this -> server_nonce ));
2012-06-13 08:53:52 +02:00
foreach ( $res as $row )
2012-06-12 10:35:49 +02:00
$urls [] = $this -> db -> getRowValue ( $row , 'server' ) .
" ?otp= " . $this -> db -> getRowValue ( $row , 'otp' ) .
" &modified= " . $this -> db -> getRowValue ( $row , 'modified' ) .
" & " . $this -> otpPartFromInfoString ( $this -> db -> getRowValue ( $row , 'info' ));
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
/*
Send out requests
*/
2009-12-08 17:07:08 +01:00
$ans_arr = $this -> retrieveURLasync ( $urls , $ans_req , $timeout );
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
if ( ! is_array ( $ans_arr )) {
2012-05-29 11:07:19 +02:00
$this -> log ( LOG_WARNING , 'No responses from validation server pool' );
2009-12-02 18:32:20 +01:00
$ans_arr = array ();
}
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
/*
Parse responses
*/
2009-12-04 12:57:49 +01:00
$localParams = $this -> localParams ;
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
$this -> answers = count ( $ans_arr );
$this -> valid_answers = 0 ;
foreach ( $ans_arr as $answer ){
2009-12-04 11:58:37 +01:00
/* Parse out parameters from each response */
2009-12-02 18:32:20 +01:00
$resParams = $this -> parseParamsFromMultiLineString ( $answer );
2010-01-13 13:32:38 +01:00
$this -> log ( LOG_DEBUG , " local db contains " , $localParams );
$this -> log ( LOG_DEBUG , " response contains " , $resParams );
$this -> log ( LOG_DEBUG , " OTP contains " , $this -> otpParams );
2009-12-07 18:21:38 +01:00
/* Update internal DB (conditional) */
2012-05-29 11:07:19 +02:00
2009-12-07 18:21:38 +01:00
$this -> updateDbCounters ( $resParams );
2012-05-29 11:07:19 +02:00
/* Check for warnings
2010-01-14 10:39:48 +01:00
See http :// code . google . com / p / yubikey - val - server - php / wiki / ServerReplicationProtocol
2012-05-29 11:07:19 +02:00
2010-01-14 10:39:48 +01:00
NOTE : We use localParams for validationParams comparison since they are actually the
2012-05-29 11:07:19 +02:00
same in this situation and we have them at hand .
2009-12-04 11:58:37 +01:00
*/
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
if ( $this -> countersHigherThan ( $localParams , $resParams )) {
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_NOTICE , " Remote server out of sync " );
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
if ( $this -> countersHigherThan ( $resParams , $localParams )) {
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_NOTICE , " Local server out of sync " );
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
if ( $this -> CountersEqual ( $resParams , $localParams ) &&
2010-01-14 10:39:48 +01:00
$resParams [ 'nonce' ] != $localParams [ 'nonce' ]) {
$this -> log ( LOG_NOTICE , " Servers out of sync. Nonce differs. " );
}
2009-12-15 11:17:51 +01:00
2012-05-29 11:07:19 +02:00
if ( $this -> CountersEqual ( $resParams , $localParams ) &&
2010-01-14 10:39:48 +01:00
$resParams [ 'modified' ] != $localParams [ 'modified' ]) {
$this -> log ( LOG_NOTICE , " Servers out of sync. Modified differs. " );
}
2012-05-29 11:07:19 +02:00
2010-01-14 10:39:48 +01:00
if ( $this -> countersHigherThan ( $resParams , $this -> otpParams )){
$this -> log ( LOG_WARNING , 'OTP is replayed. Sync response counters higher than OTP counters.' );
2012-05-29 11:07:19 +02:00
}
2010-01-14 10:39:48 +01:00
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.' );
2009-12-15 11:17:51 +01:00
} else {
2012-05-29 11:07:19 +02:00
2009-12-15 11:17:51 +01:00
/* The answer is ok since a REPLAY was not indicated */
2012-05-29 11:07:19 +02:00
2009-12-15 11:17:51 +01:00
$this -> valid_answers ++ ;
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
/* Delete entry from table */
2009-12-07 14:33:24 +01:00
$this -> deleteQueueEntry ( $answer );
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
/*
2010-01-08 14:54:33 +01:00
NULL queued_time for remaining entries in queue , to allow
daemon to take care of them as soon as possible . */
2012-05-29 11:07:19 +02:00
$this -> db -> updateBy ( 'queue' , 'server_nonce' , $this -> server_nonce ,
2010-01-08 14:54:33 +01:00
array ( 'queued' => NULL ));
2012-05-29 11:07:19 +02:00
/* 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 .
2009-12-02 18:32:20 +01:00
Otherwise , return false . */
if ( $this -> valid_answers == $ans_req ) return True ;
else return False ;
}
2010-02-22 14:01:49 +01:00
2009-12-02 18:32:20 +01:00
public function getNumberOfValidAnswers ()
{
if ( isset ( $this -> valid_answers )) return $this -> valid_answers ;
else return 0 ;
}
2010-02-22 14:01:49 +01:00
2009-12-02 18:32:20 +01:00
public function getNumberOfAnswers ()
{
if ( isset ( $this -> answers )) return $this -> answers ;
else return 0 ;
}
2009-12-04 11:58:37 +01:00
/*
This function takes a list of URLs . It will return the content of
the first successfully retrieved URL , whose content matches ^ OK .
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
2012-05-29 11:07:19 +02:00
URLs fail , data from some URL that did not match parameter $match
2009-12-04 11:58:37 +01:00
( defaults to ^ OK ) is returned , or if all URLs failed , false .
*/
2009-12-07 16:31:33 +01:00
function retrieveURLasync ( $urls , $ans_req = 1 , $timeout = 1.0 ) {
2009-12-04 11:58:37 +01:00
$mh = curl_multi_init ();
$ch = array ();
foreach ( $urls as $id => $url ) {
2010-01-14 10:39:48 +01:00
$this -> log ( LOG_DEBUG , " url in retrieveURLasync is " . $url );
2009-12-04 11:58:37 +01:00
$handle = curl_init ();
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
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 );
2009-12-07 20:13:20 +01:00
curl_setopt ( $handle , CURLOPT_TIMEOUT , $timeout );
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
curl_multi_add_handle ( $mh , $handle );
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
$ch [ $handle ] = $handle ;
}
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
$str = false ;
$ans_count = 0 ;
$ans_arr = array ();
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
do {
while (( $mrc = curl_multi_exec ( $mh , $active )) == CURLM_CALL_MULTI_PERFORM )
;
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
while ( $info = curl_multi_info_read ( $mh )) {
debug ( " YK-KSM multi " , $info );
2012-05-21 08:49:42 +02:00
if ( $info [ 'result' ] == CURLE_OK ) {
2009-12-04 11:58:37 +01:00
$str = curl_multi_getcontent ( $info [ 'handle' ]);
if ( preg_match ( " /status=OK/ " , $str )) {
$error = curl_error ( $info [ 'handle' ]);
$errno = curl_errno ( $info [ 'handle' ]);
$cinfo = curl_getinfo ( $info [ 'handle' ]);
debug ( " YK-KSM errno/error: " . $errno . " / " . $error , $cinfo );
$ans_count ++ ;
$ans_arr [] = " url= " . $cinfo [ 'url' ] . " \n " . $str ;
}
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
if ( $ans_count >= $ans_req ) {
foreach ( $ch as $h ) {
curl_multi_remove_handle ( $mh , $h );
curl_close ( $h );
}
curl_multi_close ( $mh );
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
return $ans_arr ;
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
curl_multi_remove_handle ( $mh , $info [ 'handle' ]);
curl_close ( $info [ 'handle' ]);
unset ( $ch [ $info [ 'handle' ]]);
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
2009-12-07 20:13:20 +01:00
curl_multi_select ( $mh );
2009-12-02 18:32:20 +01:00
}
2009-12-04 11:58:37 +01:00
} while ( $active );
2009-12-04 17:11:00 +01:00
2012-05-29 11:07:19 +02:00
2009-12-04 11:58:37 +01:00
foreach ( $ch as $h ) {
curl_multi_remove_handle ( $mh , $h );
curl_close ( $h );
2009-12-02 18:32:20 +01:00
}
2009-12-04 11:58:37 +01:00
curl_multi_close ( $mh );
2009-12-04 17:11:00 +01:00
if ( $ans_count > 0 ) return $ans_arr ;
else return $str ;
2009-12-02 18:32:20 +01:00
}
2012-05-29 11:07:19 +02:00
2009-12-02 18:32:20 +01:00
}
2010-02-22 14:01:49 +01:00
?>