2013-04-17 17:24:50 +02:00
< ? php
2015-07-20 22:01:16 +02:00
# Copyright (c) 2009-2015 Yubico AB
2013-04-17 17:24:50 +02:00
# 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.
require_once 'ykval-common.php' ;
require_once 'ykval-config.php' ;
require_once 'ykval-synclib.php' ;
2015-07-15 15:38:22 +02:00
header ( 'content-type: text/plain' );
2013-04-17 17:24:50 +02:00
2015-07-16 23:46:59 +02:00
$ipaddr = $_SERVER [ 'REMOTE_ADDR' ];
$allowed = $baseParams [ '__YKVAL_ALLOWED_SYNC_POOL__' ];
2015-07-16 23:44:35 +02:00
$myLog = new Log ( 'ykval-sync' );
$myLog -> addField ( 'ip' , $ipaddr );
2015-07-15 15:38:22 +02:00
$myLog -> log ( LOG_INFO , 'Request: ' . $_SERVER [ 'QUERY_STRING' ]);
2015-07-17 00:10:28 +02:00
$myLog -> log ( LOG_DEBUG , " Received request from $ipaddr " );
2013-04-17 17:24:50 +02:00
2015-09-09 15:17:01 +02:00
if ( empty ( $_SERVER [ 'QUERY_STRING' ]))
{
2020-02-19 09:20:18 +01:00
sendResp ( S_MISSING_PARAMETER , $myLog );
2015-09-09 15:17:01 +02:00
}
2013-04-17 17:24:50 +02:00
2015-07-16 23:41:22 +02:00
// verify request sent by whitelisted address
2015-07-17 00:21:16 +02:00
if ( in_array ( $ipaddr , $allowed , TRUE ) === FALSE )
{
2020-02-19 09:20:18 +01:00
$myLog -> log ( LOG_NOTICE , " Operation not allowed from IP $ipaddr " );
$myLog -> log ( LOG_DEBUG , " Remote IP $ipaddr not listed in allowed sync pool : " . implode ( ', ' , $allowed ));
sendResp ( S_OPERATION_NOT_ALLOWED , $myLog );
2013-04-17 17:24:50 +02:00
}
2015-07-16 23:56:12 +02:00
// define requirements on protocol
2015-07-15 15:38:22 +02:00
$syncParams = array (
2020-02-19 09:20:18 +01:00
'modified' => NULL ,
'otp' => NULL ,
'nonce' => NULL ,
'yk_publicname' => NULL ,
'yk_counter' => NULL ,
'yk_use' => NULL ,
'yk_high' => NULL ,
'yk_low' => NULL
2015-07-15 15:38:22 +02:00
);
2013-04-17 17:24:50 +02:00
2015-07-16 23:56:12 +02:00
// extract values from HTTP request
2015-07-17 00:10:28 +02:00
$tmp_log = 'Received ' ;
2015-07-17 00:11:07 +02:00
foreach ( $syncParams as $param => $value )
{
2020-02-19 09:20:18 +01:00
$value = getHttpVal ( $param , NULL , $_GET );
2015-07-17 00:11:07 +02:00
2020-02-19 09:20:18 +01:00
if ( $value == NULL )
{
$myLog -> log ( LOG_NOTICE , " Received request with parameter[s] ( $param ) missing value " );
sendResp ( S_MISSING_PARAMETER , $myLog );
}
2015-07-17 00:11:07 +02:00
2020-02-19 09:20:18 +01:00
$syncParams [ $param ] = $value ;
$tmp_log .= " $param = $value " ;
2013-04-17 17:24:50 +02:00
}
$myLog -> log ( LOG_INFO , $tmp_log );
2015-07-16 23:56:12 +02:00
2015-07-17 00:03:41 +02:00
$sync = new SyncLib ( 'ykval-sync:synclib' );
$sync -> addField ( 'ip' , $ipaddr );
2015-07-17 00:21:16 +02:00
if ( ! $sync -> isConnected ())
{
2020-02-19 09:20:18 +01:00
sendResp ( S_BACKEND_ERROR , $myLog );
2015-07-17 00:03:41 +02:00
}
2015-07-16 23:56:12 +02:00
// at this point we should have the otp so let's add it to the logging module
2013-04-17 17:24:50 +02:00
$myLog -> addField ( 'otp' , $syncParams [ 'otp' ]);
2015-07-16 23:56:12 +02:00
2019-11-07 19:30:34 +01:00
// Verify correctness of numeric input parameters
2015-07-16 23:17:29 +02:00
foreach ( array ( 'modified' , 'yk_counter' , 'yk_use' , 'yk_high' , 'yk_low' ) as $param )
{
2020-02-19 09:20:18 +01:00
// -1 is valid except for modified
if ( $param !== 'modified' && $syncParams [ $param ] === '-1' )
continue ;
2015-07-16 23:10:48 +02:00
2020-02-19 09:20:18 +01:00
// [0-9]+
if ( $syncParams [ $param ] !== '' && ctype_digit ( $syncParams [ $param ]))
continue ;
2015-07-16 23:10:48 +02:00
2020-02-19 09:20:18 +01:00
$myLog -> log ( LOG_NOTICE , " Input parameters $param not correct " );
sendResp ( S_MISSING_PARAMETER , $myLog );
2013-04-17 17:24:50 +02:00
}
2019-11-07 19:30:34 +01:00
// Verify correctness of OTP input
if ( ! is_otp ( $syncParams [ 'otp' ])) {
2020-02-19 09:20:18 +01:00
$myLog -> log ( LOG_NOTICE , " Input parameter " . $syncParams [ 'otp' ] . " not correct " );
sendResp ( S_MISSING_PARAMETER , $myLog );
2019-11-07 19:30:34 +01:00
}
// Verify correctness of pubid input
if ( ! is_pubid ( $syncParams [ 'yk_publicname' ])) {
2020-02-19 09:20:18 +01:00
$myLog -> log ( LOG_NOTICE , " Input parameter " . $syncParams [ 'yk_publicname' ] . " not correct " );
sendResp ( S_MISSING_PARAMETER , $myLog );
2019-11-07 19:30:34 +01:00
}
// Verify correctness of nonce input
if ( ! is_nonce ( $syncParams [ 'nonce' ])) {
2020-02-19 09:20:18 +01:00
$myLog -> log ( LOG_NOTICE , " Input parameter " . $syncParams [ 'nonce' ] . " not correct " );
sendResp ( S_MISSING_PARAMETER , $myLog );
2019-11-07 19:30:34 +01:00
}
2015-07-16 23:56:12 +02:00
// get local counter data
2019-11-07 19:30:34 +01:00
$sync -> addField ( 'otp' , $syncParams [ 'otp' ]);
2013-04-17 17:24:50 +02:00
$yk_publicname = $syncParams [ 'yk_publicname' ];
2015-07-17 23:12:59 +02:00
if (( $localParams = $sync -> getLocalParams ( $yk_publicname )) === FALSE )
2015-07-17 00:21:16 +02:00
{
2020-02-19 09:20:18 +01:00
$myLog -> log ( LOG_NOTICE , " Invalid Yubikey $yk_publicname " );
sendResp ( S_BACKEND_ERROR , $myLog );
2013-04-17 17:24:50 +02:00
}
2015-07-16 23:56:12 +02:00
// conditional update local database
2013-04-17 17:24:50 +02:00
$sync -> updateDbCounters ( $syncParams );
2015-07-15 15:38:22 +02:00
$myLog -> log ( LOG_DEBUG , 'Local params ' , $localParams );
$myLog -> log ( LOG_DEBUG , 'Sync request params ' , $syncParams );
2013-04-17 17:24:50 +02:00
2015-07-17 00:21:16 +02:00
if ( $sync -> countersHigherThan ( $localParams , $syncParams ))
{
2020-02-19 09:20:18 +01:00
$myLog -> log ( LOG_WARNING , 'Remote server out of sync.' );
2013-04-17 17:24:50 +02:00
}
2015-07-17 00:21:16 +02:00
if ( $sync -> countersEqual ( $localParams , $syncParams ))
{
2020-02-19 09:20:18 +01:00
if ( $syncParams [ 'modified' ] == $localParams [ 'modified' ]
&& $syncParams [ 'nonce' ] == $localParams [ 'nonce' ])
{
/**
* 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' );
}
if ( $syncParams [ 'modified' ] != $localParams [ 'modified' ]
&& $syncParams [ 'nonce' ] == $localParams [ 'nonce' ])
{
$deltaModified = $syncParams [ 'modified' ] - $localParams [ 'modified' ];
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 " );
}
}
if ( $syncParams [ 'nonce' ] != $localParams [ 'nonce' ])
{
$myLog -> log ( LOG_WARNING , 'Remote server has received a request to validate an already validated OTP' );
}
2013-04-17 17:24:50 +02:00
}
2015-07-17 00:21:16 +02:00
if ( $localParams [ 'active' ] != 1 )
{
2020-02-19 09:20:18 +01:00
/**
* 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!!! " );
sendResp ( S_BAD_OTP , $myLog );
2013-04-17 17:24:50 +02:00
}
2015-07-15 15:38:22 +02:00
$extra = array (
2020-02-19 09:20:18 +01:00
'modified' => $localParams [ 'modified' ],
'nonce' => $localParams [ 'nonce' ],
'yk_publicname' => $yk_publicname ,
'yk_counter' => $localParams [ 'yk_counter' ],
'yk_use' => $localParams [ 'yk_use' ],
'yk_high' => $localParams [ 'yk_high' ],
'yk_low' => $localParams [ 'yk_low' ]
2015-07-15 15:38:22 +02:00
);
2013-04-17 17:24:50 +02:00
2015-07-16 23:34:35 +02:00
sendResp ( S_OK , $myLog , '' , $extra );