2009-12-02 18:32:20 +01:00
< ? php
2013-02-04 17:36:04 +01:00
# Copyright (c) 2009-2013 Yubico AB
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2009-12-02 18:32:20 +01:00
require_once 'ykval-common.php' ;
require_once 'ykval-config.php' ;
2009-12-15 11:17:51 +01:00
require_once 'ykval-synclib.php' ;
2009-12-02 18:32:20 +01:00
$apiKey = '' ;
header ( " content-type: text/plain " );
2012-06-13 09:32:38 +02:00
2010-01-11 13:06:00 +01:00
$myLog = new Log ( 'ykval-sync' );
2010-01-14 12:25:17 +01:00
$myLog -> addField ( 'ip' , $_SERVER [ 'REMOTE_ADDR' ]);
2012-06-14 15:15:47 +02:00
if ( empty ( $_SERVER [ 'QUERY_STRING' ])) {
sendResp ( S_MISSING_PARAMETER , $myLog , $apiKey );
exit ;
}
2010-01-11 13:06:00 +01:00
$myLog -> log ( LOG_INFO , " Request: " . $_SERVER [ 'QUERY_STRING' ]);
$sync = new SyncLib ( 'ykval-sync:synclib' );
2010-01-14 12:58:19 +01:00
$sync -> addField ( 'ip' , $_SERVER [ 'REMOTE_ADDR' ]);
2009-12-02 18:32:20 +01:00
2009-12-15 11:17:51 +01:00
if ( ! $sync -> isConnected ()) {
2012-06-14 15:15:47 +02:00
sendResp ( S_BACKEND_ERROR , $myLog , $apiKey );
2009-12-02 18:32:20 +01:00
exit ;
2013-02-13 11:19:29 +01:00
}
2009-12-02 18:32:20 +01:00
2012-05-29 11:07:19 +02:00
#
2010-01-11 11:25:25 +01:00
# Verify that request comes from valid server
#
2012-06-18 12:42:39 +02:00
$myLog -> log ( LOG_INFO , 'Received request from ' . $_SERVER [ 'REMOTE_ADDR' ]);
2013-02-13 11:19:29 +01:00
$allowed = in_array ( $_SERVER [ 'REMOTE_ADDR' ], $baseParams [ '__YKVAL_ALLOWED_SYNC_POOL__' ]);
2010-01-11 11:25:25 +01:00
if ( ! $allowed ) {
2010-01-11 13:06:00 +01:00
$myLog -> log ( LOG_NOTICE , 'Operation not allowed from IP ' . $_SERVER [ 'REMOTE_ADDR' ]);
2012-06-18 12:42:39 +02:00
$myLog -> log ( LOG_DEBUG , 'Remote IP ' . $_SERVER [ 'REMOTE_ADDR' ] . ' not listed in allowed sync pool : ' .
implode ( ', ' , $baseParams [ '__YKVAL_ALLOWED_SYNC_POOL__' ]));
2012-06-14 15:15:47 +02:00
sendResp ( S_OPERATION_NOT_ALLOWED , $myLog , $apiKey );
2010-01-11 11:25:25 +01:00
exit ;
2013-02-13 11:19:29 +01:00
}
2010-01-11 11:25:25 +01:00
2009-12-02 18:32:20 +01:00
#
2013-02-13 11:19:29 +01:00
# Define requirements on protocol
2009-12-02 18:32:20 +01:00
#
2009-12-15 11:17:51 +01:00
$syncParams = array ( 'modified' => Null ,
'otp' => Null ,
'nonce' => Null ,
2010-01-08 14:54:33 +01:00
'yk_publicname' => Null ,
2009-12-15 11:17:51 +01:00
'yk_counter' => Null ,
'yk_use' => Null ,
'yk_high' => Null ,
'yk_low' => Null );
2009-12-02 18:32:20 +01:00
#
# Extract values from HTTP request
#
2010-01-11 13:06:00 +01:00
$tmp_log = " Received " ;
2009-12-02 18:32:20 +01:00
foreach ( $syncParams as $param => $value ) {
$value = getHttpVal ( $param , Null );
if ( $value == Null ) {
2012-06-12 14:50:31 +02:00
$myLog -> log ( LOG_NOTICE , " Received request with parameter[s] ( " . $param . " ) missing value " );
2012-06-14 15:15:47 +02:00
sendResp ( S_MISSING_PARAMETER , $myLog , $apiKey );
2009-12-02 18:32:20 +01:00
exit ;
}
$syncParams [ $param ] = $value ;
2010-04-23 19:36:23 +02:00
$tmp_log .= " $param = $value " ;
2009-12-02 18:32:20 +01:00
}
2010-01-11 13:06:00 +01:00
$myLog -> log ( LOG_INFO , $tmp_log );
2009-12-02 18:32:20 +01:00
2010-01-14 12:25:17 +01:00
#
2013-02-13 11:19:29 +01:00
# At this point we should have the otp so let's add it to the logging module
2010-01-14 12:25:17 +01:00
#
$myLog -> addField ( 'otp' , $syncParams [ 'otp' ]);
2010-01-14 12:58:19 +01:00
$sync -> addField ( 'otp' , $syncParams [ 'otp' ]);
2010-01-14 12:25:17 +01:00
2010-01-14 10:39:48 +01:00
#
2012-05-29 11:07:19 +02:00
# Verify correctness of input parameters
2010-01-14 10:39:48 +01:00
#
2010-01-25 15:55:05 +01:00
foreach ( array ( 'modified' ) as $param ) {
if ( preg_match ( " /^[0-9]+ $ / " , $syncParams [ $param ]) == 0 ) {
$myLog -> log ( LOG_NOTICE , 'Input parameters ' . $param . ' not correct' );
2012-06-14 15:15:47 +02:00
sendResp ( S_MISSING_PARAMETER , $myLog , $apiKey );
2010-01-25 15:55:05 +01:00
exit ;
}
}
foreach ( array ( 'yk_counter' , 'yk_use' , 'yk_high' , 'yk_low' ) as $param ) {
if ( preg_match ( " /^(-1|[0-9]+) $ / " , $syncParams [ $param ]) == 0 ) {
2010-01-14 10:39:48 +01:00
$myLog -> log ( LOG_NOTICE , 'Input parameters ' . $param . ' not correct' );
2012-06-14 15:15:47 +02:00
sendResp ( S_MISSING_PARAMETER , $myLog , $apiKey );
2010-01-14 10:39:48 +01:00
exit ;
}
}
2009-12-02 18:32:20 +01:00
#
# Get local counter data
#
2010-01-08 14:54:33 +01:00
$yk_publicname = $syncParams [ 'yk_publicname' ];
$localParams = $sync -> getLocalParams ( $yk_publicname );
2009-12-15 11:17:51 +01:00
if ( ! $localParams ) {
2012-06-12 14:21:56 +02:00
$myLog -> log ( LOG_NOTICE , 'Invalid Yubikey ' . $yk_publicname );
2012-06-14 15:15:47 +02:00
sendResp ( S_BACKEND_ERROR , $myLog , $apiKey );
2009-12-15 11:17:51 +01:00
exit ;
2013-02-13 11:19:29 +01:00
}
2009-12-15 11:17:51 +01:00
2010-01-14 10:39:48 +01:00
/* Conditional update local database */
2012-05-29 11:07:19 +02:00
$sync -> updateDbCounters ( $syncParams );
2010-01-14 10:39:48 +01:00
$myLog -> log ( LOG_DEBUG , 'Local params ' , $localParams );
$myLog -> log ( LOG_DEBUG , 'Sync request params ' , $syncParams );
2009-12-02 18:32:20 +01:00
#
2012-05-29 11:07:19 +02:00
# Compare sync and local counters and generate warnings according to
#
2013-02-04 17:06:32 +01:00
# https://github.com/Yubico/yubikey-val/wiki/ServerReplicationProtocol
2009-12-02 18:32:20 +01:00
#
2009-12-15 11:17:51 +01:00
2010-01-13 13:32:38 +01:00
2009-12-15 11:17:51 +01:00
if ( $sync -> countersHigherThan ( $localParams , $syncParams )) {
2010-01-13 13:32:38 +01:00
$myLog -> log ( LOG_WARNING , 'Remote server out of sync.' );
2013-02-13 11:19:29 +01:00
}
2009-12-15 11:17:51 +01:00
2010-01-14 10:39:48 +01:00
2009-12-15 11:17:51 +01:00
if ( $sync -> countersEqual ( $localParams , $syncParams )) {
2010-01-14 10:39:48 +01:00
if ( $syncParams [ 'modified' ] == $localParams [ 'modified' ] &&
$syncParams [ 'nonce' ] == $localParams [ 'nonce' ]) {
2012-06-13 10:10:04 +02:00
/* This is not an error . When the remote server received an OTP to verify , it would
* have sent out sync requests immediately . When the required number of responses had
* been received , the current implementation discards all additional responses ( to
* return the result to the client as soon as possible ) . If our response sent last
* time was discarded , we will end up here when the background ykval - queue processes
* the sync request again .
*/
$myLog -> log ( LOG_INFO , 'Sync request unnecessarily sent' );
2009-12-15 11:17:51 +01:00
}
2012-05-29 11:07:19 +02:00
2010-01-14 10:39:48 +01:00
if ( $syncParams [ 'modified' ] != $localParams [ 'modified' ] &&
$syncParams [ 'nonce' ] == $localParams [ 'nonce' ]) {
$deltaModified = $syncParams [ 'modified' ] - $localParams [ 'modified' ];
2012-06-14 16:44:19 +02:00
if ( $deltaModified < - 1 || $deltaModified > 1 ) {
$myLog -> log ( LOG_WARNING , 'We might have a replay. 2 events at different times have generated the same counters. The time difference is ' . $deltaModified . ' seconds' );
}
2010-01-14 10:39:48 +01:00
}
2009-12-15 11:17:51 +01:00
if ( $syncParams [ 'nonce' ] != $localParams [ 'nonce' ]) {
2010-01-14 10:39:48 +01:00
$myLog -> log ( LOG_WARNING , 'Remote server has received a request to validate an already validated OTP ' );
2009-12-02 18:32:20 +01:00
}
2013-02-13 11:19:29 +01:00
}
2009-12-02 18:32:20 +01:00
2012-06-14 13:30:04 +02:00
if ( $localParams [ 'active' ] != 1 ) {
/* The remote server has accepted an OTP from a YubiKey which we would not .
* We still needed to update our counters with the counters from the OTP though .
*/
$myLog -> log ( LOG_WARNING , 'Received sync-request for de-activated Yubikey ' . $yk_publicname .
' - check database synchronization!!!' );
2012-06-15 11:59:42 +02:00
sendResp ( S_BAD_OTP , $myLog , $apiKey );
2012-06-14 13:30:04 +02:00
exit ;
}
2012-05-29 11:07:19 +02:00
2009-12-15 11:17:51 +01:00
$extra = array ( 'modified' => $localParams [ 'modified' ],
'nonce' => $localParams [ 'nonce' ],
2010-01-08 14:54:33 +01:00
'yk_publicname' => $yk_publicname ,
2009-12-15 11:17:51 +01:00
'yk_counter' => $localParams [ 'yk_counter' ],
'yk_use' => $localParams [ 'yk_use' ],
'yk_high' => $localParams [ 'yk_high' ],
'yk_low' => $localParams [ 'yk_low' ]);
2012-06-14 15:15:47 +02:00
sendResp ( S_OK , $myLog , $apiKey , $extra );
2009-12-02 18:32:20 +01:00
?>