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

Re-indent everything according to PEAR standard

This commit is contained in:
Nigel Williams 2020-02-19 09:20:18 +01:00
parent d0e4db3245
commit 2c133de5f3
No known key found for this signature in database
GPG Key ID: 669BF2ED84BDDE8B
26 changed files with 2350 additions and 2358 deletions

View File

@ -30,18 +30,18 @@
$verbose = 0;
if (isset($argv[1])) {
if ($argv[1] == "-h" || $argv[1] == "--help") {
print "Usage: " . $argv[0] . " [-h|--help] [-v]\n";
exit(1);
}
if ($argv[1] == "-h" || $argv[1] == "--help") {
print "Usage: " . $argv[0] . " [-h|--help] [-v]\n";
exit(1);
}
if ($argv[1] && $argv[1] != "-v") {
print $argv[0] . ": invalid option -- '" . $argv[0] . "'\n";
print "Try `" . $argv[0] . " --help' for more information.\n";
exit(1);
}
if ($argv[1] && $argv[1] != "-v") {
print $argv[0] . ": invalid option -- '" . $argv[0] . "'\n";
print "Try `" . $argv[0] . " --help' for more information.\n";
exit(1);
}
$verbose = $argv[1] == "-v";
$verbose = $argv[1] == "-v";
}
set_include_path(implode(PATH_SEPARATOR, array(
@ -59,30 +59,30 @@ $myLog = new Log($logname);
$db = Db::GetDatabaseHandle($baseParams, $logname);
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
}
$everything = "";
$result=$db->customQuery("SELECT id, active, secret ".
"FROM clients ".
"ORDER BY id");
"FROM clients ".
"ORDER BY id");
while($row = $db->fetchArray($result)) {
$active = $row['active'];
if ($active == "") {
# For some reason PostgreSQL returns empty strings for false values?!
$active = "0";
}
$everything .=
$row['id'] . "\t" . $active . "\t" .
$row['secret'] . "\n";
$active = $row['active'];
if ($active == "") {
# For some reason PostgreSQL returns empty strings for false values?!
$active = "0";
}
$everything .=
$row['id'] . "\t" . $active . "\t" .
$row['secret'] . "\n";
}
$db->closeCursor($result);
$hash = sha1 ($everything);
if ($verbose) {
print $everything;
print $everything;
}
print substr ($hash, 0, 10) . "\n";

View File

@ -30,18 +30,18 @@
$verbose = 0;
if (isset($argv[1])) {
if ($argv[1] == "-h" || $argv[1] == "--help") {
print "Usage: " . $argv[0] . " [-h|--help] [-v]\n";
exit(1);
}
if ($argv[1] == "-h" || $argv[1] == "--help") {
print "Usage: " . $argv[0] . " [-h|--help] [-v]\n";
exit(1);
}
if ($argv[1] && $argv[1] != "-v") {
print $argv[0] . ": invalid option -- '" . $argv[0] . "'\n";
print "Try `" . $argv[0] . " --help' for more information.\n";
exit(1);
}
if ($argv[1] && $argv[1] != "-v") {
print $argv[0] . ": invalid option -- '" . $argv[0] . "'\n";
print "Try `" . $argv[0] . " --help' for more information.\n";
exit(1);
}
$verbose = $argv[1] == "-v";
$verbose = $argv[1] == "-v";
}
set_include_path(implode(PATH_SEPARATOR, array(
@ -59,24 +59,24 @@ $myLog = new Log($logname);
$db = Db::GetDatabaseHandle($baseParams, $logname);
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
}
$everything = "";
$result=$db->customQuery("SELECT yk_publicname, yk_counter, yk_use ".
"FROM yubikeys WHERE active = false ".
"ORDER BY yk_publicname");
"FROM yubikeys WHERE active = false ".
"ORDER BY yk_publicname");
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
$everything .=
$row['yk_publicname'] . "\t" . $row['yk_counter'] . "\t" . $row['yk_use'] .
"\n";
$everything .=
$row['yk_publicname'] . "\t" . $row['yk_counter'] . "\t" . $row['yk_use'] .
"\n";
}
$hash = sha1 ($everything);
if ($verbose) {
print $everything;
print $everything;
}
print substr ($hash, 0, 10) . "\n";

View File

@ -53,104 +53,104 @@ define('INT32_LEN', 10);
function logdie ($logger, $str)
{
$logger->log(LOG_INFO, $str);
die($str . "\n");
$logger->log(LOG_INFO, $str);
die($str . "\n");
}
function getHttpVal ($key, $default, $a)
{
if (array_key_exists($key, $a))
{
$val = $a[$key];
}
else
{
$val = $default;
}
if (array_key_exists($key, $a))
{
$val = $a[$key];
}
else
{
$val = $default;
}
$val = trim($val);
$val = str_replace('\\', '', $val);
$val = trim($val);
$val = str_replace('\\', '', $val);
return $val;
return $val;
}
// Verifies if a given string is modhex
function is_modhex($s) {
if (preg_match('/^[cbdefghijklnrtuv]+$/', $s) === 0) {
return false;
} else {
return true;
}
if (preg_match('/^[cbdefghijklnrtuv]+$/', $s) === 0) {
return false;
} else {
return true;
}
}
// Verifies if a given string is a valid OTP
function is_otp($otp) {
if ($otp == "") {
return false;
}
$otp_len = strlen($otp);
return $otp_len >= TOKEN_LEN && $otp_len <= OTP_MAX_LEN && is_modhex($otp);
if ($otp == "") {
return false;
}
$otp_len = strlen($otp);
return $otp_len >= TOKEN_LEN && $otp_len <= OTP_MAX_LEN && is_modhex($otp);
}
// Verifies if a given string is a valid public id
function is_pubid($id) {
$id_len = strlen($id);
return $id_len >= 0 && $id_len <= PUBID_MAX_LEN && is_modhex($id);
$id_len = strlen($id);
return $id_len >= 0 && $id_len <= PUBID_MAX_LEN && is_modhex($id);
}
// Verifies a given string is a valid nonce
function is_nonce($nonce) {
return strlen($nonce) >= NONCE_MIN_LEN
&& strlen($nonce) <= NONCE_MAX_LEN
&& ctype_alnum($nonce);
return strlen($nonce) >= NONCE_MIN_LEN
&& strlen($nonce) <= NONCE_MAX_LEN
&& ctype_alnum($nonce);
}
// Verifies if a given string is a valid client id
function is_clientid($id) {
if ($id == "0") {
return false;
}
return strlen($id) <= INT32_LEN && ctype_digit($id);
if ($id == "0") {
return false;
}
return strlen($id) <= INT32_LEN && ctype_digit($id);
}
// Sign a http query string in the array of key-value pairs
// return b64 encoded hmac hash
function sign($a, $apiKey, $logger)
{
ksort($a);
ksort($a);
$qs = http_build_query($a);
$qs = urldecode($qs);
$qs = utf8_encode($qs);
$qs = http_build_query($a);
$qs = urldecode($qs);
$qs = utf8_encode($qs);
// base64 encoded binary digest
$hmac = hash_hmac('sha1', $qs, $apiKey, TRUE);
$hmac = base64_encode($hmac);
// base64 encoded binary digest
$hmac = hash_hmac('sha1', $qs, $apiKey, TRUE);
$hmac = base64_encode($hmac);
$logger->log(LOG_DEBUG, "SIGN: $qs H=$hmac");
$logger->log(LOG_DEBUG, "SIGN: $qs H=$hmac");
return $hmac;
return $hmac;
}
function curl_settings($logger, $ident, $ch, $url, $timeout, $opts)
{
$logger->log(LOG_DEBUG, "$ident adding URL : $url");
$logger->log(LOG_DEBUG, "$ident adding URL : $url");
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_USERAGENT, 'YK-VAL');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FAILONERROR, TRUE);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_USERAGENT, 'YK-VAL');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FAILONERROR, TRUE);
if (is_array($opts) === FALSE)
{
$logger->log(LOG_WARN, $ident . 'curl options must be an array');
return;
}
if (is_array($opts) === FALSE)
{
$logger->log(LOG_WARN, $ident . 'curl options must be an array');
return;
}
foreach ($opts as $key => $val)
if (curl_setopt($ch, $key, $val) === FALSE)
$logger->log(LOG_WARN, "$ident failed to set " . curl_opt_name($key));
foreach ($opts as $key => $val)
if (curl_setopt($ch, $key, $val) === FALSE)
$logger->log(LOG_WARN, "$ident failed to set " . curl_opt_name($key));
}
// returns the string name of a curl constant,
@ -160,16 +160,16 @@ function curl_settings($logger, $ident, $ch, $url, $timeout, $opts)
// curl_opt_name(CURLOPT_BLABLA) returns "curl option"
function curl_opt_name($opt)
{
$consts = get_defined_constants(true);
$consts = $consts['curl'];
$consts = get_defined_constants(true);
$consts = $consts['curl'];
$name = array_search($opt, $consts, TRUE);
$name = array_search($opt, $consts, TRUE);
// array_search may return either on failure...
if ($name === FALSE || $name === NULL)
return 'curl option';
// array_search may return either on failure...
if ($name === FALSE || $name === NULL)
return 'curl option';
return $name;
return $name;
}
// This function takes a list of URLs. It will return the content of
@ -181,164 +181,164 @@ function curl_opt_name($opt)
// (defaults to ^OK) is returned, or if all URLs failed, false.
function retrieveURLasync($ident, $urls, $logger, $ans_req=1, $match="^OK", $returl=False, $timeout=10, $curlopts)
{
$mh = curl_multi_init();
$ch = array();
$mh = curl_multi_init();
$ch = array();
foreach ($urls as $url)
{
$handle = curl_init();
curl_settings($logger, $ident, $handle, $url, $timeout, $curlopts);
curl_multi_add_handle($mh, $handle);
$ch[(int) $handle] = $handle;
}
foreach ($urls as $url)
{
$handle = curl_init();
curl_settings($logger, $ident, $handle, $url, $timeout, $curlopts);
curl_multi_add_handle($mh, $handle);
$ch[(int) $handle] = $handle;
}
$ans_arr = array();
$ans_arr = array();
do
{
while (curl_multi_exec($mh, $active) == CURLM_CALL_MULTI_PERFORM);
do
{
while (curl_multi_exec($mh, $active) == CURLM_CALL_MULTI_PERFORM);
while ($info = curl_multi_info_read($mh))
{
$logger->log(LOG_DEBUG, "$ident curl multi info : ", $info);
while ($info = curl_multi_info_read($mh))
{
$logger->log(LOG_DEBUG, "$ident curl multi info : ", $info);
if ($info['result'] == CURLE_OK)
{
$str = curl_multi_getcontent($info['handle']);
if ($info['result'] == CURLE_OK)
{
$str = curl_multi_getcontent($info['handle']);
$logger->log(LOG_DEBUG, "$ident curl multi content : $str");
$logger->log(LOG_DEBUG, "$ident curl multi content : $str");
if (preg_match("/$match/", $str))
{
$logger->log(LOG_DEBUG, "$ident response matches $match");
$error = curl_error($info['handle']);
$errno = curl_errno($info['handle']);
$cinfo = curl_getinfo($info['handle']);
$logger->log(LOG_INFO, "$ident errno/error: $errno/$error", $cinfo);
if (preg_match("/$match/", $str))
{
$logger->log(LOG_DEBUG, "$ident response matches $match");
$error = curl_error($info['handle']);
$errno = curl_errno($info['handle']);
$cinfo = curl_getinfo($info['handle']);
$logger->log(LOG_INFO, "$ident errno/error: $errno/$error", $cinfo);
if ($returl)
$ans_arr[] = "url=" . $cinfo['url'] . "\n" . $str;
else
$ans_arr[] = $str;
}
if ($returl)
$ans_arr[] = "url=" . $cinfo['url'] . "\n" . $str;
else
$ans_arr[] = $str;
}
if (count($ans_arr) >= $ans_req)
{
foreach ($ch as $h)
{
curl_multi_remove_handle($mh, $h);
curl_close($h);
}
curl_multi_close($mh);
if (count($ans_arr) >= $ans_req)
{
foreach ($ch as $h)
{
curl_multi_remove_handle($mh, $h);
curl_close($h);
}
curl_multi_close($mh);
return $ans_arr;
}
return $ans_arr;
}
curl_multi_remove_handle($mh, $info['handle']);
curl_close($info['handle']);
unset($ch[(int) $info['handle']]);
}
curl_multi_remove_handle($mh, $info['handle']);
curl_close($info['handle']);
unset($ch[(int) $info['handle']]);
}
curl_multi_select($mh);
}
}
while($active);
curl_multi_select($mh);
}
}
while($active);
foreach ($ch as $h)
{
curl_multi_remove_handle($mh, $h);
curl_close($h);
}
curl_multi_close($mh);
foreach ($ch as $h)
{
curl_multi_remove_handle($mh, $h);
curl_close($h);
}
curl_multi_close($mh);
if (count($ans_arr) > 0)
return $ans_arr;
if (count($ans_arr) > 0)
return $ans_arr;
return false;
return false;
}
function KSMdecryptOTP($urls, $logger, $curlopts)
{
$response = retrieveURLasync('YK-KSM', $urls, $logger, $ans_req=1, $match='^OK', $returl=False, $timeout=10, $curlopts);
$response = retrieveURLasync('YK-KSM', $urls, $logger, $ans_req=1, $match='^OK', $returl=False, $timeout=10, $curlopts);
if ($response === FALSE)
return false;
if ($response === FALSE)
return false;
$response = array_shift($response);
$response = array_shift($response);
$logger->log(LOG_DEBUG, "YK-KSM response: $response");
$logger->log(LOG_DEBUG, "YK-KSM response: $response");
$ret = array();
$ret = array();
if (sscanf($response,
'OK counter=%04x low=%04x high=%02x use=%02x',
$ret['session_counter'],
$ret['low'],
$ret['high'],
$ret['session_use']) !== 4)
{
return false;
}
if (sscanf($response,
'OK counter=%04x low=%04x high=%02x use=%02x',
$ret['session_counter'],
$ret['low'],
$ret['high'],
$ret['session_use']) !== 4)
{
return false;
}
return $ret;
return $ret;
}
function sendResp($status, $logger, $apiKey = '', $extra = null)
{
if ($logger->request !== NULL)
$logger->request->set('status', $status);
if ($logger->request !== NULL)
$logger->request->set('status', $status);
$a['status'] = $status;
$a['status'] = $status;
// 2008-11-21T06:11:55Z0711
$t = substr(microtime(false), 2, 3);
$t = gmdate('Y-m-d\TH:i:s\Z0') . $t;
// 2008-11-21T06:11:55Z0711
$t = substr(microtime(false), 2, 3);
$t = gmdate('Y-m-d\TH:i:s\Z0') . $t;
$a['t'] = $t;
$a['t'] = $t;
if ($extra)
foreach ($extra as $param => $value)
$a[$param] = $value;
if ($extra)
foreach ($extra as $param => $value)
$a[$param] = $value;
$h = sign($a, $apiKey, $logger);
$h = sign($a, $apiKey, $logger);
$str = "";
$str .= "h=" . $h . "\r\n";
$str .= "t=" . $a['t'] . "\r\n";
$str = "";
$str .= "h=" . $h . "\r\n";
$str .= "t=" . $a['t'] . "\r\n";
if ($extra)
foreach ($extra as $param => $value)
$str .= $param . "=" . $value . "\r\n";
if ($extra)
foreach ($extra as $param => $value)
$str .= $param . "=" . $value . "\r\n";
$str .= "status=" . $a['status'] . "\r\n";
$str .= "\r\n";
$str .= "status=" . $a['status'] . "\r\n";
$str .= "\r\n";
$logger->log(LOG_INFO, "Response: " . $str . " (at " . gmdate("c") . " " . microtime() . ")");
$logger->log(LOG_INFO, "Response: " . $str . " (at " . gmdate("c") . " " . microtime() . ")");
if ($logger->request !== NULL)
$logger->request->write();
if ($logger->request !== NULL)
$logger->request->write();
echo $str;
exit;
echo $str;
exit;
}
// backport from PHP 5.6
if (function_exists('hash_equals') === FALSE)
{
function hash_equals($a, $b)
{
// hashes are a (known) fixed length,
// so this doesn't leak anything.
if (strlen($a) != strlen($b))
return false;
function hash_equals($a, $b)
{
// hashes are a (known) fixed length,
// so this doesn't leak anything.
if (strlen($a) != strlen($b))
return false;
$result = 0;
$result = 0;
for ($i = 0; $i < strlen($a); $i++)
$result |= ord($a[$i]) ^ ord($b[$i]);
for ($i = 0; $i < strlen($a); $i++)
$result |= ord($a[$i]) ^ ord($b[$i]);
return (0 === $result);
}
return (0 === $result);
}
}
/**
@ -349,33 +349,33 @@ if (function_exists('hash_equals') === FALSE)
*/
function total_time ($url)
{
$opts = array(
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => 3,
CURLOPT_FORBID_REUSE => TRUE,
CURLOPT_FRESH_CONNECT => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_USERAGENT => 'ykval-munin-vallatency/1.0',
);
$opts = array(
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => 3,
CURLOPT_FORBID_REUSE => TRUE,
CURLOPT_FRESH_CONNECT => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_USERAGENT => 'ykval-munin-vallatency/1.0',
);
if (($ch = curl_init()) === FALSE)
return false;
if (($ch = curl_init()) === FALSE)
return false;
if (curl_setopt_array($ch, $opts) === FALSE)
return false;
if (curl_setopt_array($ch, $opts) === FALSE)
return false;
// we don't care about the actual response
if (curl_exec($ch) === FALSE)
return false;
// we don't care about the actual response
if (curl_exec($ch) === FALSE)
return false;
$total_time = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
$total_time = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
curl_close($ch);
curl_close($ch);
if (is_float($total_time) === FALSE)
return false;
if (is_float($total_time) === FALSE)
return false;
return $total_time;
return $total_time;
}
/**
@ -386,38 +386,38 @@ function total_time ($url)
*/
function endpoints ($urls)
{
$endpoints = array();
$endpoints = array();
foreach ($urls as $url)
{
// internal munin name must be a-zA-Z0-9_,
// so sha1 hex should be fine.
//
// munin also truncates at some length,
// so we just take the first few characters of the hashsum.
$internal = substr(sha1($url), 0, 20);
foreach ($urls as $url)
{
// internal munin name must be a-zA-Z0-9_,
// so sha1 hex should be fine.
//
// munin also truncates at some length,
// so we just take the first few characters of the hashsum.
$internal = substr(sha1($url), 0, 20);
// actual label name shown for graph values
if (($label = hostport($url)) === FALSE)
{
return false;
}
// actual label name shown for graph values
if (($label = hostport($url)) === FALSE)
{
return false;
}
$endpoints[] = array($internal, $label, $url);
}
$endpoints[] = array($internal, $label, $url);
}
// check for truncated sha1 collisions (or actual duplicate URLs!)
$internal = array();
// check for truncated sha1 collisions (or actual duplicate URLs!)
$internal = array();
foreach($endpoints as $endpoint)
{
$internal[] = $endpoint[0];
}
foreach($endpoints as $endpoint)
{
$internal[] = $endpoint[0];
}
if (count(array_unique($internal)) !== count($endpoints))
return false;
if (count(array_unique($internal)) !== count($endpoints))
return false;
return $endpoints;
return $endpoints;
}
/**
@ -430,22 +430,22 @@ function endpoints ($urls)
*/
function hostport ($url)
{
if (($url = parse_url($url)) === FALSE)
return false;
if (($url = parse_url($url)) === FALSE)
return false;
if (array_key_exists('host', $url) === FALSE || $url['host'] === NULL)
return false;
if (array_key_exists('host', $url) === FALSE || $url['host'] === NULL)
return false;
if (array_key_exists('port', $url) === TRUE && $url['port'] !== NULL)
return $url['host'].':'.$url['port'];
if (array_key_exists('port', $url) === TRUE && $url['port'] !== NULL)
return $url['host'].':'.$url['port'];
if (array_key_exists('scheme', $url) === TRUE
&& strtolower($url['scheme']) === 'http')
return $url['host'].':80';
if (array_key_exists('scheme', $url) === TRUE
&& strtolower($url['scheme']) === 'http')
return $url['host'].':80';
if (array_key_exists('scheme', $url) === TRUE
&& strtolower($url['scheme']) === 'https')
return $url['host'].':443';
if (array_key_exists('scheme', $url) === TRUE
&& strtolower($url['scheme']) === 'https')
return $url['host'].':443';
return $url['host'];
return $url['host'];
}

View File

@ -36,17 +36,17 @@ $dbfile = '/etc/yubico/val/config-db.php';
if (file_exists($dbfile) && @is_readable($dbfile))
{
require_once $dbfile;
require_once $dbfile;
}
else
{
// FIXME hostname
// FIXME port
// 'oci:oracledb' for Oracle DB (with OCI library)
$dbtype = 'mysql';
$dbuser = 'ykval_verifier';
$dbpass = 'yourpassword';
$dbname = 'ykval';
// FIXME hostname
// FIXME port
// 'oci:oracledb' for Oracle DB (with OCI library)
$dbtype = 'mysql';
$dbuser = 'ykval_verifier';
$dbpass = 'yourpassword';
$dbname = 'ykval';
}
// for the validation interface.
@ -58,9 +58,9 @@ $baseParams['__YKVAL_DB_OPTIONS__'] = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EX
// for the validation server sync
$baseParams['__YKVAL_SYNC_POOL__'] = array(
// "https://api2.example.com/wsapi/2.0/sync",
// "https://api3.example.com/wsapi/2.0/sync",
// "https://api4.example.com/wsapi/2.0/sync",
// "https://api2.example.com/wsapi/2.0/sync",
// "https://api3.example.com/wsapi/2.0/sync",
// "https://api4.example.com/wsapi/2.0/sync",
);
/**
@ -70,12 +70,12 @@ $baseParams['__YKVAL_SYNC_POOL__'] = array(
* Both IPv4 and IPv6 are supported.
*/
$baseParams['__YKVAL_ALLOWED_SYNC_POOL__'] = array(
// "1.2.3.4",
// "2.3.4.5",
// "3.4.5.6",
// "fc00:aaaa::",
// "fc00:bbbb::",
// "fc00:cccc::",
// "1.2.3.4",
// "2.3.4.5",
// "3.4.5.6",
// "fc00:aaaa::",
// "fc00:bbbb::",
// "fc00:cccc::",
);
// An array of IP addresses allowed to issue YubiKey activation/deactivation
@ -103,33 +103,33 @@ $baseParams['__YKVAL_SYNC_DEFAULT_TIMEOUT__'] = 1;
// A key -> value array with curl options to set
// when calling URLs defined in __YKVAL_SYNC_POOL__
$baseParams['__YKVAL_SYNC_CURL_OPTS__'] = array(
//CURLOPT_PROTOCOLS => CURLPROTO_HTTP,
//CURLOPT_PROTOCOLS => CURLPROTO_HTTP,
);
// A key -> value array with curl options to set
// when calling URLs returned by otp2ksmurls()
$baseParams['__YKVAL_KSM_CURL_OPTS__'] = array(
//CURLOPT_PROTOCOLS => CURLPROTO_HTTP,
//CURLOPT_PROTOCOLS => CURLPROTO_HTTP,
);
// Returns an array of YK-KSM URLs for decrypting $otp for $client.
// The URLs must be fully qualified, i.e., containing the OTP itself.
function otp2ksmurls ($otp, $client)
{
//if ($client == 42) {
// return array("https://another-ykksm.example.com/wsapi/decrypt?otp=$otp");
//}
//if ($client == 42) {
// return array("https://another-ykksm.example.com/wsapi/decrypt?otp=$otp");
//}
//if (preg_match("/^dteffujehknh/", $otp)) {
// return array("https://different-ykksm.example.com/wsapi/decrypt?otp=$otp");
//}
//if (preg_match("/^dteffujehknh/", $otp)) {
// return array("https://different-ykksm.example.com/wsapi/decrypt?otp=$otp");
//}
return array(
// "https://ykksm1.example.com/wsapi/decrypt?otp=$otp",
// "https://ykksm2.example.com/wsapi/decrypt?otp=$otp",
"http://127.0.0.1:80/wsapi/decrypt?otp=$otp",
"http://127.0.0.1:8002/wsapi/decrypt?otp=$otp",
);
return array(
// "https://ykksm1.example.com/wsapi/decrypt?otp=$otp",
// "https://ykksm2.example.com/wsapi/decrypt?otp=$otp",
"http://127.0.0.1:80/wsapi/decrypt?otp=$otp",
"http://127.0.0.1:8002/wsapi/decrypt?otp=$otp",
);
}
/**

View File

@ -36,224 +36,224 @@ require_once('ykval-db.php');
class DbImpl extends Db
{
/**
* Constructor
*
* @param string $host Database host
* @param string $user Database user
* @param string $pwd Database password
* @param string $name Database table name
* @return void
*
*/
public function __construct($db_dsn, $db_username, $db_password, $db_options, $name='ykval-db')
{
$this->db_dsn=$db_dsn;
$this->db_username=$db_username;
$this->db_password=$db_password;
$this->db_options=$db_options;
/**
* Constructor
*
* @param string $host Database host
* @param string $user Database user
* @param string $pwd Database password
* @param string $name Database table name
* @return void
*
*/
public function __construct($db_dsn, $db_username, $db_password, $db_options, $name='ykval-db')
{
$this->db_dsn=$db_dsn;
$this->db_username=$db_username;
$this->db_password=$db_password;
$this->db_options=$db_options;
if(substr($db_dsn, 0, 4) == 'oci:') {
# "oci:" prefix needs to be removed before passing db_dsn to OCI
$this->db_dsn = substr($this->db_dsn, 4);
}
$this->myLog=new Log($name);
}
/**
* function to connect to database defined in config.php
*
* @return boolean True on success, otherwise false.
*
*/
public function connect(){
$this->dbh = oci_connect($this->db_username, $this->db_password, $this->db_dsn);
if (!$this->dbh) {
$error = oci_error();
$this->myLog->log(LOG_CRIT, "Database connection error: " . $error["message"]);
$this->dbh=Null;
return false;
}
return true;
}
protected function query($query, $returnresult=false) {
if(!$this->isConnected()) {
$this->connect();
}
if($this->isConnected()) {
$this->myLog->log(LOG_DEBUG, 'DB query is: ' . $query);
# OCI mode
$result = oci_parse($this->dbh, $query);
if(!oci_execute($result)) {
$this->myLog->log(LOG_INFO, 'Database query error: ' . preg_replace('/\n/',' ',print_r(oci_error($result), true)));
$this->dbh = Null;
return false;
}
$this->result = $result;
if ($returnresult) return $this->result;
else return true;
} else {
$this->myLog->log(LOG_CRIT, 'No database connection');
return false;
}
}
/**
* function to get a row from the query result
* Once all rows have been fetch, function closeCursor needs to be called
*
* @param object $result Query result object or null to use the current one
* @return array a query row
*
*/
public function fetchArray($result=null){
if(!$result) $result = $this->result;
if(!$result) return null;
$res = oci_fetch_array($result, OCI_ASSOC);
return array_change_key_case($res, CASE_LOWER);
}
/**
* function to close the cursor after having fetched rows
*
* @param object $result Query result object or null to use the current one
*
*/
public function closeCursor($result=null){
}
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
* @return mixed Array with values from Db row or 2d-array with multiple rows
*
*/
public function findByMultiple($table, $where, $nr=null, $rev=null, $distinct=null)
{
$value=""; /* quiet the PHP Notice */
$match=null; /* quiet the PHP Notice */
$query="SELECT";
if($nr!=null){
# LIMIT doesn't exist in Oracle, so we encapsulate the query to be
# able to filter a given number of rows afterwars (after ordering)
$query.= " * FROM (SELECT";
}
if ($distinct!=null) {
$query.= " DISTINCT " . $distinct;
} else {
$query.= " *";
}
$query.= " FROM " . $table;
if ($where!=null){
foreach ($where as $key=>$value) {
if ($key != 'server' && !(ctype_alnum($value) || is_null($value)))
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted to use non-alphanumeric in WHERE: " . $table . "." . $key . " = " . $value);
return false;
if(substr($db_dsn, 0, 4) == 'oci:') {
# "oci:" prefix needs to be removed before passing db_dsn to OCI
$this->db_dsn = substr($this->db_dsn, 4);
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted use invalid URL in WHERE: " . $table . "." . $key . " = " . $value);
return false;
$this->myLog=new Log($name);
}
/**
* function to connect to database defined in config.php
*
* @return boolean True on success, otherwise false.
*
*/
public function connect(){
$this->dbh = oci_connect($this->db_username, $this->db_password, $this->db_dsn);
if (!$this->dbh) {
$error = oci_error();
$this->myLog->log(LOG_CRIT, "Database connection error: " . $error["message"]);
$this->dbh=Null;
return false;
}
if ($key!=null) {
if ($value!=null) $match.= " ". $key . " = '" . $value . "' and";
else $match.= " ". $key . " is NULL and";
return true;
}
protected function query($query, $returnresult=false) {
if(!$this->isConnected()) {
$this->connect();
}
}
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 .= ") WHERE rownum < " . ($nr+1);
}
$result = $this->query($query, true);
if (!$result) return false;
if ($nr==1) {
$row = $this->fetchArray($result);
$this->closeCursor($result);
return $row;
}
else {
$collection=array();
while($row = $this->fetchArray($result)){
$collection[]=$row;
}
$this->closeCursor($result);
return $collection;
}
}
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
* @return boolean True on success, otherwise false.
*
*/
public function deleteByMultiple($table, $where, $nr=null, $rev=null)
{
$query="DELETE";
$query.= " FROM " . $table;
$query .= " WHERE id IN (SELECT id FROM " . $table;
if ($where!=null){
$query.= " WHERE";
foreach ($where as $key=>$value) {
if ($key != 'server' && !ctype_alnum($value))
{
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write non-alphanumeric to the database: " . $value);
return false;
if($this->isConnected()) {
$this->myLog->log(LOG_DEBUG, 'DB query is: ' . $query);
# OCI mode
$result = oci_parse($this->dbh, $query);
if(!oci_execute($result)) {
$this->myLog->log(LOG_INFO, 'Database query error: ' . preg_replace('/\n/',' ',print_r(oci_error($result), true)));
$this->dbh = Null;
return false;
}
$this->result = $result;
if ($returnresult) return $this->result;
else return true;
} else {
$this->myLog->log(LOG_CRIT, 'No database connection');
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write invalid URL to the database: " . $value);
return false;
}
/**
* function to get a row from the query result
* Once all rows have been fetch, function closeCursor needs to be called
*
* @param object $result Query result object or null to use the current one
* @return array a query row
*
*/
public function fetchArray($result=null){
if(!$result) $result = $this->result;
if(!$result) return null;
$res = oci_fetch_array($result, OCI_ASSOC);
return array_change_key_case($res, CASE_LOWER);
}
/**
* Function to close the cursor after having fetched rows
*
* @param object $result Query result object or null to use the current one
*
*/
public function closeCursor($result=null){
}
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
* @return mixed Array with values from Db row or 2d-array with multiple rows
*
*/
public function findByMultiple($table, $where, $nr=null, $rev=null, $distinct=null)
{
$value=""; /* quiet the PHP Notice */
$match=null; /* quiet the PHP Notice */
$query="SELECT";
if($nr!=null){
# LIMIT doesn't exist in Oracle, so we encapsulate the query to be
# able to filter a given number of rows afterwars (after ordering)
$query.= " * FROM (SELECT";
}
if ($distinct!=null) {
$query.= " DISTINCT " . $distinct;
} else {
$query.= " *";
}
$query.= " FROM " . $table;
if ($where!=null){
foreach ($where as $key=>$value) {
if ($key != 'server' && !(ctype_alnum($value) || is_null($value)))
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted to use non-alphanumeric in WHERE: " . $table . "." . $key . " = " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted use invalid URL in WHERE: " . $table . "." . $key . " = " . $value);
return false;
}
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 .= ") WHERE rownum < " . ($nr+1);
}
$result = $this->query($query, true);
if (!$result) return false;
if ($nr==1) {
$row = $this->fetchArray($result);
$this->closeCursor($result);
return $row;
}
else {
$collection=array();
while($row = $this->fetchArray($result)){
$collection[]=$row;
}
$this->closeCursor($result);
return $collection;
}
$query.= " ". $key . " = '" . $value . "' and";
}
$query=rtrim($query, "and");
$query=rtrim($query);
}
if ($rev==1) $query.= " ORDER BY id DESC";
$query .= ")";
if ($nr!=null) $query.= " and rownum < " . ($nr+1);
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
* @return boolean True on success, otherwise false.
*
*/
public function deleteByMultiple($table, $where, $nr=null, $rev=null)
{
$query="DELETE";
$query.= " FROM " . $table;
$query .= " WHERE id IN (SELECT id FROM " . $table;
if ($where!=null){
$query.= " WHERE";
foreach ($where as $key=>$value) {
if ($key != 'server' && !ctype_alnum($value))
{
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write non-alphanumeric to the database: " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write invalid URL to the database: " . $value);
return false;
}
$query.= " ". $key . " = '" . $value . "' and";
}
$query=rtrim($query, "and");
$query=rtrim($query);
}
if ($rev==1) $query.= " ORDER BY id DESC";
return $this->query($query, false);
}
$query .= ")";
if ($nr!=null) $query.= " and rownum < " . ($nr+1);
/**
* Function to get the number of rows
*
* @param object $result Query result object or null to use the current one
* @return int number of rows affected by last statement or 0 if database connection is not functional.
*
*/
public function rowCount($result=null)
{
if(!$result) $result = $this->result;
if($result) {
return oci_num_rows($result);
} else {
return 0;
return $this->query($query, false);
}
/**
* Function to get the number of rows
*
* @param object $result Query result object or null to use the current one
* @return int number of rows affected by last statement or 0 if database connection is not functional.
*
*/
public function rowCount($result=null)
{
if(!$result) $result = $this->result;
if($result) {
return oci_num_rows($result);
} else {
return 0;
}
}
}
}

View File

@ -36,231 +36,228 @@ require_once('ykval-db.php');
class DbImpl extends Db
{
/**
* Constructor
*
* @param string $host Database host
* @param string $user Database user
* @param string $pwd Database password
* @param string $name Database table name
* @return void
*
*/
public function __construct($db_dsn, $db_username, $db_password, $db_options, $name='ykval-db')
{
$this->db_dsn=$db_dsn;
$this->db_username=$db_username;
$this->db_password=$db_password;
$this->db_options=$db_options;
$this->result = null;
/**
* Constructor
*
* @param string $host Database host
* @param string $user Database user
* @param string $pwd Database password
* @param string $name Database table name
* @return void
*
*/
public function __construct($db_dsn, $db_username, $db_password, $db_options, $name='ykval-db')
{
$this->db_dsn=$db_dsn;
$this->db_username=$db_username;
$this->db_password=$db_password;
$this->db_options=$db_options;
$this->result = null;
$this->myLog=new Log($name);
}
/**
* function to connect to database defined in config.php
*
* @return boolean True on success, otherwise false.
*
*/
public function connect(){
try {
$this->dbh = new PDO($this->db_dsn, $this->db_username, $this->db_password, $this->db_options);
} catch (PDOException $e) {
$this->myLog->log(LOG_CRIT, "Database connection error: " . $e->getMessage());
$this->dbh=Null;
return false;
$this->myLog=new Log($name);
}
return true;
}
protected function query($query, $returnresult=false) {
if(!$this->isConnected()) {
$this->connect();
/**
* function to connect to database defined in config.php
*
* @return boolean True on success, otherwise false.
*
*/
public function connect(){
try {
$this->dbh = new PDO($this->db_dsn, $this->db_username, $this->db_password, $this->db_options);
} catch (PDOException $e) {
$this->myLog->log(LOG_CRIT, "Database connection error: " . $e->getMessage());
$this->dbh=Null;
return false;
}
return true;
}
if($this->isConnected()) {
$this->myLog->log(LOG_DEBUG, 'DB query is: ' . $query);
try {
$this->result = $this->dbh->query($query);
} catch (PDOException $e) {
$this->myLog->log(LOG_INFO, 'Database query error: ' . preg_replace('/\n/',' ',print_r($this->dbh->errorInfo(), true)));
$this->dbh = Null;
return false;
}
if ($returnresult) return $this->result;
else return true;
} else {
$this->myLog->log(LOG_CRIT, 'No database connection');
return false;
protected function query($query, $returnresult=false) {
if(!$this->isConnected()) {
$this->connect();
}
if($this->isConnected()) {
$this->myLog->log(LOG_DEBUG, 'DB query is: ' . $query);
try {
$this->result = $this->dbh->query($query);
} catch (PDOException $e) {
$this->myLog->log(LOG_INFO, 'Database query error: ' . preg_replace('/\n/',' ',print_r($this->dbh->errorInfo(), true)));
$this->dbh = Null;
return false;
}
if ($returnresult) return $this->result;
else return true;
} else {
$this->myLog->log(LOG_CRIT, 'No database connection');
return false;
}
}
}
/**
* function to get a row from the query result
* Once all rows have been fetch, function closeCursor needs to be called
*
* @param object $result Query result object or null to use the current one
* @return array a query row
*
*/
public function fetchArray($result=null){
if(!$result) $result = $this->result;
if(!$result) return null;
/**
* function to get a row from the query result
* Once all rows have been fetch, function closeCursor needs to be called
*
* @param object $result Query result object or null to use the current one
* @return array a query row
*
*/
public function fetchArray($result=null){
if(!$result) $result = $this->result;
if(!$result) return null;
return $result->fetch(PDO::FETCH_ASSOC);
}
return $result->fetch(PDO::FETCH_ASSOC);
}
/**
* function to close the cursor after having fetched rows
*
* @param object $result Query result object or null to use the current one
*
*/
public function closeCursor($result=null){
if(!$result) $result = $this->result;
if($result) $result->closeCursor();
}
/**
* function to close the cursor after having fetched rows
*
* @param object $result Query result object or null to use the current one
*
*/
public function closeCursor($result=null){
if(!$result) $result = $this->result;
if($result) $result->closeCursor();
}
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
*
* @return mixed Array with values from Db row or 2d-array with multiple rows
*/
public function findByMultiple($table, $where, $nr=NULL, $rev=NULL, $distinct=NULL)
{
$value = '';
$match = NULL;
$query = 'SELECT';
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
*
* @return mixed Array with values from Db row or 2d-array with multiple rows
*/
public function findByMultiple($table, $where, $nr=NULL, $rev=NULL, $distinct=NULL)
{
$value = '';
$match = NULL;
$query = 'SELECT';
if ($distinct != NULL)
$query.= " DISTINCT " . $distinct;
else
$query.= " *";
if ($distinct != NULL)
$query.= " DISTINCT " . $distinct;
else
$query.= " *";
$query.= " FROM " . $table;
$query.= " FROM " . $table;
if ($where != NULL)
{
foreach ($where as $key => $value)
{
if ($key != 'server' && !(ctype_alnum($value) || is_null($value)))
if ($where != NULL)
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted to use non-alphanumeric in WHERE: " . $table . "." . $key . " = " . $value);
return false;
foreach ($where as $key => $value)
{
if ($key != 'server' && !(ctype_alnum($value) || is_null($value)))
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted to use non-alphanumeric in WHERE: " . $table . "." . $key . " = " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted to use invalid URL in WHERE: " . $table . "." . $key . " = " . $value);
return false;
}
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);
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
if ($rev == 1)
$query.= " ORDER BY id DESC";
if ($nr != NULL)
$query.= " LIMIT " . $nr;
$result = $this->query($query, true);
if (!$result)
return false;
if ($nr == 1)
{
$this->myLog->log(LOG_WARNING, "findByMultiple: attempted to use invalid URL in WHERE: " . $table . "." . $key . " = " . $value);
return false;
$row = $this->fetchArray($result);
$this->closeCursor($result);
return $row;
}
if ($key != NULL)
{
if ($value != NULL)
$match .= " ". $key . " = '" . $value . "' and";
else
$match .= " ". $key . " is NULL and";
}
}
if ($match != NULL)
$query .= " WHERE" . $match;
$collection = array();
$query = rtrim($query, "and");
$query = rtrim($query);
}
while($row = $this->fetchArray($result))
$collection[] = $row;
if ($rev == 1)
$query.= " ORDER BY id DESC";
$this->closeCursor($result);
if ($nr != NULL)
$query.= " LIMIT " . $nr;
$result = $this->query($query, true);
if (!$result)
return false;
if ($nr == 1)
{
$row = $this->fetchArray($result);
$this->closeCursor($result);
return $row;
}
$collection = array();
while($row = $this->fetchArray($result))
$collection[] = $row;
$this->closeCursor($result);
return $collection;
}
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
* @return boolean True on success, otherwise false.
*
*/
public function deleteByMultiple($table, $where, $nr=null, $rev=null)
{
$query="DELETE";
$query.= " FROM " . $table;
if ($where!=null){
$query.= " WHERE";
foreach ($where as $key=>$value) {
if ($key != 'server' && !ctype_alnum($value)) {
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write non-alphanumeric to the database: " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write invalid URL to the database: " . $value);
return false;
}
$query.= " ". $key . " = '" . $value . "' and";
}
$query=rtrim($query, "and");
$query=rtrim($query);
return $collection;
}
if ($rev==1) $query.= " ORDER BY id DESC";
if ($nr!=null) $query.= " LIMIT " . $nr;
return $this->query($query, false);
}
/**
* Function to get the number of rows
*
* @param object $result Query result object or null to use the current one
* @return int number of rows affected by last statement or 0 if database connection is not functional.
*
*/
public function rowCount($result=null)
{
if(!$result) $result = $this->result;
if($result) {
$count=$result->rowCount();
$result->closeCursor();
return $count;
} else {
return 0;
/**
* 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
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @param string distinct Select rows with distinct columns, Default=NULL
* @return boolean True on success, otherwise false.
*
*/
public function deleteByMultiple($table, $where, $nr=null, $rev=null)
{
$query="DELETE";
$query.= " FROM " . $table;
if ($where!=null){
$query.= " WHERE";
foreach ($where as $key=>$value) {
if ($key != 'server' && !ctype_alnum($value)) {
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write non-alphanumeric to the database: " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "deleteByMultiple: attempted to write invalid URL to the database: " . $value);
return false;
}
$query.= " ". $key . " = '" . $value . "' and";
}
$query=rtrim($query, "and");
$query=rtrim($query);
}
if ($rev==1) $query.= " ORDER BY id DESC";
if ($nr!=null) $query.= " LIMIT " . $nr;
return $this->query($query, false);
}
/**
* Function to get the number of rows
*
* @param object $result Query result object or null to use the current one
* @return int number of rows affected by last statement or 0 if database connection is not functional.
*
*/
public function rowCount($result=null)
{
if(!$result) $result = $this->result;
if($result) {
$count=$result->rowCount();
$result->closeCursor();
return $count;
} else {
return 0;
}
}
}
}

View File

@ -35,276 +35,274 @@ require_once('ykval-log.php');
abstract class Db
{
/**
* static function to determine database type and instantiate the correct subclass
*
* */
public static function GetDatabaseHandle($baseParams, $logname)
{
if(substr($baseParams['__YKVAL_DB_DSN__'], 0, 3) == 'oci') {
require_once 'ykval-db-oci.php';
} else {
require_once 'ykval-db-pdo.php';
}
return new DbImpl($baseParams['__YKVAL_DB_DSN__'],
/**
* static function to determine database type and instantiate the correct subclass
*
* */
public static function GetDatabaseHandle($baseParams, $logname)
{
if(substr($baseParams['__YKVAL_DB_DSN__'], 0, 3) == 'oci') {
require_once 'ykval-db-oci.php';
} else {
require_once 'ykval-db-pdo.php';
}
return new DbImpl($baseParams['__YKVAL_DB_DSN__'],
$baseParams['__YKVAL_DB_USER__'],
$baseParams['__YKVAL_DB_PW__'],
$baseParams['__YKVAL_DB_OPTIONS__'],
$logname . ':db');
}
function addField($name, $value)
{
$this->myLog->addField($name, $value);
}
/**
* function to convert Db timestamps to unixtime(s)
*
* @param string $updated Database timestamp
* @return int Timestamp in unixtime format
*
*/
public function timestampToTime($updated)
{
$stamp=strptime($updated, '%F %H:%M:%S');
return mktime($stamp[tm_hour], $stamp[tm_min], $stamp[tm_sec], $stamp[tm_mon]+1, $stamp[tm_mday], $stamp[tm_year]);
}
/**
* function to compute delta (s) between 2 Db timestamps
*
* @param string $first Database timestamp 1
* @param string $second Database timestamp 2
* @return int Deltatime (s)
*
*/
public function timestampDeltaTime($first, $second)
{
return Db::timestampToTime($second) - Db::timestampToTime($first);
}
/**
* function to disconnect from database
*
* @return boolean True on success, otherwise false.
*
*/
public function disconnect()
{
$this->dbh=NULL;
}
/**
* function to check if database is connected
*
* @return boolean True if connected, otherwise false.
*
*/
public function isConnected()
{
if ($this->dbh!=NULL) return True;
else return False;
}
/**
* 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)
{
if (!ctype_alnum($v) && !filter_var($v, FILTER_VALIDATE_URL)) {
$this->myLog->log(LOG_WARNING, "updateBy: attempted to use an invalid value: " . $v);
return false;
}
$query = "";
foreach ($values as $key=>$value) {
if ($key != 'server' && !(ctype_alnum($value) || is_null($value))) {
$this->myLog->log(LOG_WARNING, "updateBy: attempted to write non-alphanumeric to the database: " . $table . "." . $key . " <= " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "updateBy: attempted to write invalid URL to the database: " . $table . "." . $key . " <= " . $value);
return false;
}
if (!is_null($value)) $query .= ' ' . $key . "='" . $value . "',";
else $query .= ' ' . $key . '=NULL,';
}
if (! $query) {
$this->myLog->log(LOG_DEBUG, "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;
return $this->query($query, false);
}
/**
* function to update row in database
*
* @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 update($table, $id, $values)
{
return $this->updateBy($table, 'id', $id, $values);
}
/**
* function to update row in database based on a condition
*
* @param string $table Database table to update row in
* @param string $k Column to select row on
* @param string $v Value to select row on
* @param array $values Array with key=>values to update
* @param string $condition conditional statement
* @return boolean True on success, otherwise false.
*
*/
public function conditionalUpdateBy($table, $k, $v, $values, $condition)
{
if (!ctype_alnum($v) || preg_match('/^[a-zA-Z0-9><=()_ ]*$/', $condition) == 0)
function addField($name, $value)
{
$this->myLog->log(LOG_WARNING, "conditionalUpdateBy: attempted to use non-alphanumeric value: " . $v . " - " . $condition);
return false;
}
$query = ""; /* quiet the PHP Notice */
foreach ($values as $key=>$value){
if ($key != 'server' && !is_int($value) && !ctype_alnum($value)) {
$this->myLog->log(LOG_WARNING, "conditionalUpdateBy: attempted to write non-alphanumeric to the database: " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "conditionalUpdateBy: attempted to write invalid URL to the database: " . $value);
return false;
}
$query = $query . " " . $key . "='" . $value . "',";
}
if (! $query) {
$this->myLog->log(LOG_DEBUG, "no values to set in query. Not updating DB");
return true;
$this->myLog->addField($name, $value);
}
$query = rtrim($query, ",") . " WHERE " . $k . " = '" . $v . "' and " . $condition;
// Insert UPDATE statement at beginning
$query = "UPDATE " . $table . " SET " . $query;
/**
* function to convert Db timestamps to unixtime(s)
*
* @param string $updated Database timestamp
* @return int Timestamp in unixtime format
*
*/
public function timestampToTime($updated)
{
$stamp=strptime($updated, '%F %H:%M:%S');
return mktime($stamp[tm_hour], $stamp[tm_min], $stamp[tm_sec], $stamp[tm_mon]+1, $stamp[tm_mday], $stamp[tm_year]);
return $this->query($query, false);
}
}
/**
* function to compute delta (s) between 2 Db timestamps
*
* @param string $first Database timestamp 1
* @param string $second Database timestamp 2
* @return int Deltatime (s)
*
*/
public function timestampDeltaTime($first, $second)
{
return Db::timestampToTime($second) - Db::timestampToTime($first);
}
/**
* Function to update row in database based on a condition.
* An ID value is passed to select the appropriate column
*
* @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
* @param string $condition conditional statement
* @return boolean True on success, otherwise false.
*
*/
public function conditionalUpdate($table, $id, $values, $condition)
{
return $this->conditionalUpdateBy($table, 'id', $id, $values, $condition);
}
/**
* function to disconnect from database
*
* @return boolean True on success, otherwise false.
*
*/
public function disconnect()
{
$this->dbh=NULL;
}
/**
* function to insert new row in database
*
* @param string $table Database table to update row in
* @param array $values Array with key=>values to update
* @return boolean True on success, otherwise false.
*
*/
public function save($table, $values)
{
$query= 'INSERT INTO ' . $table . " (";
foreach ($values as $key=>$value){
if ($key == 'server') {
$v = filter_var($value, FILTER_VALIDATE_URL);
if (!$v) {
$this->myLog->log(LOG_WARNING, "save: bad server URL provided: " . $value);
return false;
/**
* function to check if database is connected
*
* @return boolean True if connected, otherwise false.
*
*/
public function isConnected()
{
if ($this->dbh!=NULL) return True;
else return False;
}
/**
* 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)
{
if (!ctype_alnum($v) && !filter_var($v, FILTER_VALIDATE_URL)) {
$this->myLog->log(LOG_WARNING, "updateBy: attempted to use an invalid value: " . $v);
return false;
}
$value = $v;
} else if ($key == 'info') {
if (preg_match('/[a-zA-Z0-9&_=,]+/', $value) == 0) {
$this->myLog->log(LOG_WARNING, "save: bad info string provided: " . $value);
return false;
}
} else {
if ($value != '' && !is_int($value) && !ctype_alnum($value)) {
$this->myLog->log(LOG_WARNING, "save: attempted to write non-alphanumeric to the database: " . $value);
return false;
}
}
if (!is_null($value)) $query = $query . $key . ",";
}
$query = rtrim($query, ",") . ') VALUES (';
foreach ($values as $key=>$value){
if (!is_null($value)) $query = $query . "'" . $value . "',";
}
$query = rtrim($query, ",");
$query = $query . ")";
return $this->query($query, false);
}
/**
* helper function to collect last row[s] in database
*
* @param string $table Database table to update row in
* @param int $nr Number of rows to collect. NULL=>inifinity. DEFAULT=1.
* @return mixed Array with values from Db row or 2d-array with multiple rows
or false on failure.
*
*/
public function last($table, $nr=1)
{
return Db::findBy($table, null, null, $nr, 1);
}
$query = "";
/**
* 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
* @param string $value Value to select rows by
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @return mixed Array with values from Db row or 2d-array with multiple rows
*
*/
public function findBy($table, $key, $value, $nr=null, $rev=null)
{
return $this->findByMultiple($table, array($key=>$value), $nr, $rev);
}
foreach ($values as $key=>$value) {
if ($key != 'server' && !(ctype_alnum($value) || is_null($value))) {
$this->myLog->log(LOG_WARNING, "updateBy: attempted to write non-alphanumeric to the database: " . $table . "." . $key . " <= " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "updateBy: attempted to write invalid URL to the database: " . $table . "." . $key . " <= " . $value);
return false;
}
if (!is_null($value)) $query .= ' ' . $key . "='" . $value . "',";
else $query .= ' ' . $key . '=NULL,';
}
if (! $query) {
$this->myLog->log(LOG_DEBUG, "no values to set in query. Not updating DB");
return true;
}
/**
* Function to do a custom query on database connection
*
* @param string $query Database query
* @return mixed
*
*/
public function customQuery($query)
{
return $this->query($query, true);
}
$query = rtrim($query, ",") . " WHERE " . $k . " = '" . $v . "'";
// Insert UPDATE statement at beginning
$query = "UPDATE " . $table . " SET " . $query;
return $this->query($query, false);
}
/**
* function to update row in database
*
* @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 update($table, $id, $values)
{
return $this->updateBy($table, 'id', $id, $values);
}
/**
* function to update row in database based on a condition
*
* @param string $table Database table to update row in
* @param string $k Column to select row on
* @param string $v Value to select row on
* @param array $values Array with key=>values to update
* @param string $condition conditional statement
* @return boolean True on success, otherwise false.
*
*/
public function conditionalUpdateBy($table, $k, $v, $values, $condition)
{
if (!ctype_alnum($v) || preg_match('/^[a-zA-Z0-9><=()_ ]*$/', $condition) == 0)
{
$this->myLog->log(LOG_WARNING, "conditionalUpdateBy: attempted to use non-alphanumeric value: " . $v . " - " . $condition);
return false;
}
$query = ""; /* quiet the PHP Notice */
foreach ($values as $key=>$value){
if ($key != 'server' && !is_int($value) && !ctype_alnum($value)) {
$this->myLog->log(LOG_WARNING, "conditionalUpdateBy: attempted to write non-alphanumeric to the database: " . $value);
return false;
}
elseif ($key == 'server' && !filter_var($value, FILTER_VALIDATE_URL))
{
$this->myLog->log(LOG_WARNING, "conditionalUpdateBy: attempted to write invalid URL to the database: " . $value);
return false;
}
$query = $query . " " . $key . "='" . $value . "',";
}
if (! $query) {
$this->myLog->log(LOG_DEBUG, "no values to set in query. Not updating DB");
return true;
}
$query = rtrim($query, ",") . " WHERE " . $k . " = '" . $v . "' and " . $condition;
// Insert UPDATE statement at beginning
$query = "UPDATE " . $table . " SET " . $query;
return $this->query($query, false);
}
/**
* Function to update row in database based on a condition.
* An ID value is passed to select the appropriate column
*
* @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
* @param string $condition conditional statement
* @return boolean True on success, otherwise false.
*
*/
public function conditionalUpdate($table, $id, $values, $condition)
{
return $this->conditionalUpdateBy($table, 'id', $id, $values, $condition);
}
/**
* function to insert new row in database
*
* @param string $table Database table to update row in
* @param array $values Array with key=>values to update
* @return boolean True on success, otherwise false.
*
*/
public function save($table, $values)
{
$query= 'INSERT INTO ' . $table . " (";
foreach ($values as $key=>$value){
if ($key == 'server') {
$v = filter_var($value, FILTER_VALIDATE_URL);
if (!$v) {
$this->myLog->log(LOG_WARNING, "save: bad server URL provided: " . $value);
return false;
}
$value = $v;
} else if ($key == 'info') {
if (preg_match('/[a-zA-Z0-9&_=,]+/', $value) == 0) {
$this->myLog->log(LOG_WARNING, "save: bad info string provided: " . $value);
return false;
}
} else {
if ($value != '' && !is_int($value) && !ctype_alnum($value)) {
$this->myLog->log(LOG_WARNING, "save: attempted to write non-alphanumeric to the database: " . $value);
return false;
}
}
if (!is_null($value)) $query = $query . $key . ",";
}
$query = rtrim($query, ",") . ') VALUES (';
foreach ($values as $key=>$value){
if (!is_null($value)) $query = $query . "'" . $value . "',";
}
$query = rtrim($query, ",");
$query = $query . ")";
return $this->query($query, false);
}
/**
* helper function to collect last row[s] in database
*
* @param string $table Database table to update row in
* @param int $nr Number of rows to collect. NULL=>inifinity. DEFAULT=1.
* @return mixed Array with values from Db row or 2d-array with multiple rows
or false on failure.
*
*/
public function last($table, $nr=1)
{
return Db::findBy($table, null, null, $nr, 1);
}
/**
* 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
* @param string $value Value to select rows by
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
* @return mixed Array with values from Db row or 2d-array with multiple rows
*
*/
public function findBy($table, $key, $value, $nr=null, $rev=null)
{
return $this->findByMultiple($table, array($key=>$value), $nr, $rev);
}
/**
* Function to do a custom query on database connection
*
* @param string $query Database query
* @return mixed
*
*/
public function customQuery($query)
{
return $this->query($query, true);
}
}

View File

@ -29,9 +29,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set_include_path(implode(PATH_SEPARATOR, array(
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
)));
require_once 'ykval-config.php';
@ -44,24 +44,24 @@ $myLog = new Log($logname);
$db = Db::GetDatabaseHandle($baseParams, $logname);
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
}
$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 = $db->fetchArray($result)){
echo (int)$row['active'] .
"," . $row['created'] .
"," . $row['modified'] .
"," . $row['yk_publicname'] .
"," . $row['yk_counter'] .
"," . $row['yk_use'] .
"," . $row['yk_low'] .
"," . $row['yk_high'] .
"," . $row['nonce'] .
"," . $row['notes'] .
"\n";
}
echo (int)$row['active'] .
"," . $row['created'] .
"," . $row['modified'] .
"," . $row['yk_publicname'] .
"," . $row['yk_counter'] .
"," . $row['yk_use'] .
"," . $row['yk_low'] .
"," . $row['yk_high'] .
"," . $row['nonce'] .
"," . $row['notes'] .
"\n";
}
$db->closeCursor($result);
$db->disconnect();

View File

@ -44,20 +44,20 @@ $myLog = new Log($logname);
$db = Db::GetDatabaseHandle($baseParams, $logname);
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
exit(1);
}
$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 = $db->fetchArray($result)) {
echo $row['id'] .
"," . (int)$row['active'] .
"," . $row['created'] .
"," . $row['secret'] .
"," . $row['email'] .
"," . $row['notes'] .
"," . $row['otp'] .
"\n";
echo $row['id'] .
"," . (int)$row['active'] .
"," . $row['created'] .
"," . $row['secret'] .
"," . $row['email'] .
"," . $row['notes'] .
"," . $row['otp'] .
"\n";
}
$db->closeCursor($result);

View File

@ -37,18 +37,18 @@ set_include_path(implode(PATH_SEPARATOR, array(
$options = getopt("h", array("help", "email::", "notes::", "otp::", "urandom"));
if(array_key_exists('h', $options) || array_key_exists('help', $options)) {
echo "Usage: ".$argv[0]." [ OPTIONS ] [ num_clients ]\n";
echo " Unless num_clients is defined, one client will be generated.\n\n";
echo "Options supported by ".$argv[0]."\n";
echo " --urandom\n";
echo " Use /dev/urandom instead of /dev/random as entropy source\n";
echo " --email=EMAIL\n";
echo " Sets the e-mail field of the created clients\n";
echo " --notes=NOTES\n";
echo " Sets the notes field of the created clients\n";
echo " --otp=OTP\n";
echo " Sets the otp field of the created clients\n";
exit(1);
echo "Usage: ".$argv[0]." [ OPTIONS ] [ num_clients ]\n";
echo " Unless num_clients is defined, one client will be generated.\n\n";
echo "Options supported by ".$argv[0]."\n";
echo " --urandom\n";
echo " Use /dev/urandom instead of /dev/random as entropy source\n";
echo " --email=EMAIL\n";
echo " Sets the e-mail field of the created clients\n";
echo " --notes=NOTES\n";
echo " Sets the notes field of the created clients\n";
echo " --otp=OTP\n";
echo " Sets the otp field of the created clients\n";
exit(1);
}
require_once 'ykval-config.php';
@ -60,65 +60,65 @@ $myLog = new Log($logname);
$db = Db::GetDatabaseHandle($baseParams, $logname);
if(!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
}
$count=1;
if($last_arg = intval(array_pop($argv))) {
$count = $last_arg;
$count = $last_arg;
}
$result = $db->customQuery("SELECT id FROM clients ORDER BY id DESC LIMIT 1");
$row = $db->fetchArray($result);
$db->closeCursor($result);
if($row) {
$next_id = $row['id']+1;
$next_id = $row['id']+1;
} else {
$next_id = 1;
$next_id = 1;
}
$random = array_key_exists('urandom', $options) ? "/dev/urandom" : "/dev/random";
$fh = fopen($random, "r");
if(!$fh) {
die("cannot open ".$random);
die("cannot open ".$random);
}
for ($i=0; $i<$count; $i++) {
$client_id = $next_id++;
if (!($rnd = fread ($fh, 20))) {
die("cannot read from ".$random);
}
$secret = base64_encode($rnd);
$client_id = $next_id++;
if (!($rnd = fread ($fh, 20))) {
die("cannot read from ".$random);
}
$secret = base64_encode($rnd);
$params = array(
"id" => $client_id,
"active" => 1,
"created" => time(),
"secret" => $secret,
"email" => array_key_exists('email', $options) ? $options['email'] : '',
"notes" => array_key_exists('notes', $options) ? $options['notes'] : '',
"otp" => array_key_exists('otp', $options) ? $options['otp'] : ''
);
$params = array(
"id" => $client_id,
"active" => 1,
"created" => time(),
"secret" => $secret,
"email" => array_key_exists('email', $options) ? $options['email'] : '',
"notes" => array_key_exists('notes', $options) ? $options['notes'] : '',
"otp" => array_key_exists('otp', $options) ? $options['otp'] : ''
);
$query="INSERT INTO clients " .
"(id,active,created,secret,email,notes,otp) VALUES " .
"('" . $params["id"] . "', " .
"'" . $params["active"] . "', " .
"'" . $params['created'] . "'," .
"'" . $params['secret'] . "'," .
"'" . $params['email'] . "'," .
"'" . $params['notes'] . "'," .
"'" . $params['otp'] . "')";
$query="INSERT INTO clients " .
"(id,active,created,secret,email,notes,otp) VALUES " .
"('" . $params["id"] . "', " .
"'" . $params["active"] . "', " .
"'" . $params['created'] . "'," .
"'" . $params['secret'] . "'," .
"'" . $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);
exit(1);
}
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);
exit(1);
}
echo $client_id.",".$secret."\n";
echo $client_id.",".$secret."\n";
}
fclose($fh);

View File

@ -44,80 +44,80 @@ $myLog = new Log($logname);
$db = Db::GetDatabaseHandle($baseParams, $logname);
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
}
while ($res=fgetcsv(STDIN, 0, ",")) {
if ($res[0]===null || strpos($res[0], '#')===0)
continue;
if ($res[0]===null || strpos($res[0], '#')===0)
continue;
$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]
);
$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]
);
# FIXME
# INSERT first, if duplicate error, UPDATE.
# FIXME
# INSERT first, if duplicate error, UPDATE.
$query="SELECT * FROM yubikeys WHERE yk_publicname='" . $params['yk_publicname'] . "'";
$result=$db->customQuery($query);
$query="SELECT * FROM yubikeys WHERE yk_publicname='" . $params['yk_publicname'] . "'";
$result=$db->customQuery($query);
if ($db->rowCount($result)) {
$query="UPDATE yubikeys SET " .
"active='" . $params["active"] . "' " .
",created='" . $params["created"] . "' " .
",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"] . "' " .
",notes='" . $params["notes"] . "' " .
"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->rowCount($result)) {
$query="UPDATE yubikeys SET " .
"active='" . $params["active"] . "' " .
",created='" . $params["created"] . "' " .
",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"] . "' " .
",notes='" . $params["notes"] . "' " .
"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);
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 " .
"(active,created,modified,yk_publicname,yk_counter,yk_use,yk_low,yk_high,nonce,notes) VALUES " .
"('" . $params["active"] . "', " .
"'" . $params['created'] . "'," .
"'" . $params['modified'] . "'," .
"'" . $params['yk_publicname'] . "'," .
"'" . $params['yk_counter'] . "'," .
"'" . $params['yk_use'] . "'," .
"'" . $params['yk_low'] . "'," .
"'" . $params['yk_high'] . "'," .
"'" . $params['nonce'] . "'," .
"'" . $params['notes'] . "')";
else {
// We didn't have the yk_publicname in database so we need to do insert instead
$query="INSERT INTO yubikeys " .
"(active,created,modified,yk_publicname,yk_counter,yk_use,yk_low,yk_high,nonce,notes) VALUES " .
"('" . $params["active"] . "', " .
"'" . $params['created'] . "'," .
"'" . $params['modified'] . "'," .
"'" . $params['yk_publicname'] . "'," .
"'" . $params['yk_counter'] . "'," .
"'" . $params['yk_use'] . "'," .
"'" . $params['yk_low'] . "'," .
"'" . $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);
exit(1);
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);
exit(1);
}
}
}
$db->closeCursor($result);
$db->closeCursor($result);
}
$myLog->log(LOG_NOTICE, "Successfully imported yubikeys to database");

View File

@ -44,46 +44,46 @@ $myLog = new Log($logname);
$db = Db::GetDatabaseHandle($baseParams, $logname);
if (!$db->connect()) {
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
}
$myLog->log(LOG_WARNING, "Could not connect to database");
error_log("Could not connect to database");
exit(1);
}
while ($res=fgetcsv(STDIN, 0, ",")) {
if($res[0]===null || strpos($res[0], '#')===0) continue;
if($res[0]===null || strpos($res[0], '#')===0) continue;
$params=array("id"=>$res[0],
"active"=>$res[1],
"created"=>$res[2],
"secret"=>$res[3],
"email"=>$res[4],
"notes"=>$res[5],
"otp"=>$res[6]);
$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($db->rowCount($result) == 0) {
// We didn't have the id in database so we need to do insert instead
$query="INSERT INTO clients " .
"(id,active,created,secret,email,notes,otp) VALUES " .
"('" . $params["id"] . "', " .
"'" . $params["active"] . "', " .
"'" . $params['created'] . "'," .
"'" . $params['secret'] . "'," .
"'" . $params['email'] . "'," .
"'" . $params['notes'] . "'," .
"'" . $params['otp'] . "')";
$query="SELECT * FROM clients WHERE id='" . $params['id'] . "'";
$result=$db->customQuery($query);
if($db->rowCount($result) == 0) {
// We didn't have the id in database so we need to do insert instead
$query="INSERT INTO clients " .
"(id,active,created,secret,email,notes,otp) VALUES " .
"('" . $params["id"] . "', " .
"'" . $params["active"] . "', " .
"'" . $params['created'] . "'," .
"'" . $params['secret'] . "'," .
"'" . $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);
exit(1);
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);
exit(1);
}
}
}
$db->closeCursor($result);
}
$db->closeCursor($result);
}
$myLog->log(LOG_NOTICE, "Successfully imported clients to database");

View File

@ -31,153 +31,153 @@ require_once 'ykval-common.php';
class LogVerify
{
public $format = NULL;
public $format = NULL;
private $fields = array(
'time_start' => NULL,
'time_end' => NULL,
'time_taken' => NULL,
'ip' => NULL,
'client' => NULL,
'public_id' => NULL,
'otp' => NULL,
'status' => NULL,
'nonce' => NULL,
'signed' => NULL,
'counter' => NULL,
'low' => NULL,
'high' => NULL,
'use' => NULL,
'tls' => NULL,
'protocol' => NULL,
'sl' => NULL,
'timeout' => NULL,
);
private $fields = array(
'time_start' => NULL,
'time_end' => NULL,
'time_taken' => NULL,
'ip' => NULL,
'client' => NULL,
'public_id' => NULL,
'otp' => NULL,
'status' => NULL,
'nonce' => NULL,
'signed' => NULL,
'counter' => NULL,
'low' => NULL,
'high' => NULL,
'use' => NULL,
'tls' => NULL,
'protocol' => NULL,
'sl' => NULL,
'timeout' => NULL,
);
/**
* Set field value.
*
* @param $name string
* @param $value mixed
* @return bool
*/
public function set($name, $value)
{
// not settable from outside
if ($name === 'time_end' || $name === 'time_taken')
return false;
/**
* Set field value.
*
* @param $name string
* @param $value mixed
* @return bool
*/
public function set($name, $value)
{
// not settable from outside
if ($name === 'time_end' || $name === 'time_taken')
return false;
if (array_key_exists($name, $this->fields) === FALSE)
return false;
if (array_key_exists($name, $this->fields) === FALSE)
return false;
$this->fields[$name] = $value;
return true;
}
$this->fields[$name] = $value;
return true;
}
/**
* Write verify request log line to syslog.
*
* @return bool
*/
public function write()
{
if ($this->format === NULL)
return false;
/**
* Write verify request log line to syslog.
*
* @return bool
*/
public function write()
{
if ($this->format === NULL)
return false;
$values = array();
foreach ($this->sanitized() as $key => $val)
{
$values['%'.$key.'%'] = $val;
}
$values = array();
foreach ($this->sanitized() as $key => $val)
{
$values['%'.$key.'%'] = $val;
}
$message = strtr($this->format, $values);
$message = strtr($this->format, $values);
if (!is_string($message))
return false;
if (!is_string($message))
return false;
return syslog(LOG_INFO, $message);
}
return syslog(LOG_INFO, $message);
}
/**
* Sanitize untrusted values from clients before writing them to syslog.
*
* P.S. signed, status, time_start, tls are assumed safe,
* since they are set internally.
*
* @return array sanitized $this->fields
*/
private function sanitized()
{
$a = $this->fields;
/**
* Sanitize untrusted values from clients before writing them to syslog.
*
* P.S. signed, status, time_start, tls are assumed safe,
* since they are set internally.
*
* @return array sanitized $this->fields
*/
private function sanitized()
{
$a = $this->fields;
if (preg_match('/^[cbdefghijklnrtuv]+$/', $a['public_id']) !== 1
|| strlen($a['public_id']) < 1
|| strlen($a['public_id']) > (OTP_MAX_LEN - TOKEN_LEN))
{
$a['public_id'] = '-';
}
if (preg_match('/^[cbdefghijklnrtuv]+$/', $a['public_id']) !== 1
|| strlen($a['public_id']) < 1
|| strlen($a['public_id']) > (OTP_MAX_LEN - TOKEN_LEN))
{
$a['public_id'] = '-';
}
if (preg_match('/^[cbdefghijklnrtuv]+$/', $a['otp']) !== 1
|| strlen($a['otp']) < TOKEN_LEN
|| strlen($a['otp']) > OTP_MAX_LEN)
{
$a['otp'] = '-';
}
if (preg_match('/^[cbdefghijklnrtuv]+$/', $a['otp']) !== 1
|| strlen($a['otp']) < TOKEN_LEN
|| strlen($a['otp']) > OTP_MAX_LEN)
{
$a['otp'] = '-';
}
if (preg_match('/^[0-9]+$/', $a['client']) !== 1)
$a['client'] = '-';
if (preg_match('/^[0-9]+$/', $a['client']) !== 1)
$a['client'] = '-';
if (filter_var($a['ip'], FILTER_VALIDATE_IP) === FALSE)
$a['ip'] = '-';
if (filter_var($a['ip'], FILTER_VALIDATE_IP) === FALSE)
$a['ip'] = '-';
if (is_int($a['counter']) === FALSE)
$a['counter'] = '-';
if (is_int($a['counter']) === FALSE)
$a['counter'] = '-';
if (is_int($a['low']) === FALSE)
$a['low'] = '-';
if (is_int($a['low']) === FALSE)
$a['low'] = '-';
if (is_int($a['high']) === FALSE)
$a['high'] = '-';
if (is_int($a['high']) === FALSE)
$a['high'] = '-';
if (is_int($a['use']) === FALSE)
$a['use'] = '-';
if (is_int($a['use']) === FALSE)
$a['use'] = '-';
if (preg_match('/^[a-zA-Z0-9]{16,40}$/', $a['nonce']) !== 1)
$a['nonce'] = '-';
if (preg_match('/^[a-zA-Z0-9]{16,40}$/', $a['nonce']) !== 1)
$a['nonce'] = '-';
if (is_float($a['protocol']) === TRUE)
$a['protocol'] = sprintf('%.1f', $a['protocol']);
else
$a['protocol'] = '-';
if (is_float($a['protocol']) === TRUE)
$a['protocol'] = sprintf('%.1f', $a['protocol']);
else
$a['protocol'] = '-';
if ( $a['sl'] !== 'fast'
&& $a['sl'] !== 'secure'
&& (preg_match('/^[0-9]{1,3}$/', $a['sl']) !== 1 || (((int) $a['sl']) > 100)))
{
$a['sl'] = '-';
}
if ( $a['sl'] !== 'fast'
&& $a['sl'] !== 'secure'
&& (preg_match('/^[0-9]{1,3}$/', $a['sl']) !== 1 || (((int) $a['sl']) > 100)))
{
$a['sl'] = '-';
}
if (preg_match('/^[0-9]+$/', $a['timeout']) !== 1)
$a['timeout'] = '-';
if (preg_match('/^[0-9]+$/', $a['timeout']) !== 1)
$a['timeout'] = '-';
$start = explode(' ', $a['time_start']);
$start_msec = $start[0];
$start_sec = $start[1];
$start = bcadd($start_sec, $start_msec, 8);
unset($start_sec, $start_msec);
$start = explode(' ', $a['time_start']);
$start_msec = $start[0];
$start_sec = $start[1];
$start = bcadd($start_sec, $start_msec, 8);
unset($start_sec, $start_msec);
$end = explode(' ', microtime());
$end_msec = $end[0];
$end_sec = $end[1];
$end = bcadd($end_sec, $end_msec, 8);
unset($end_sec, $end_msec);
$end = explode(' ', microtime());
$end_msec = $end[0];
$end_sec = $end[1];
$end = bcadd($end_sec, $end_msec, 8);
unset($end_sec, $end_msec);
$taken = bcsub($end, $start, 8);
$taken = bcsub($end, $start, 8);
$a['time_start'] = $start;
$a['time_end'] = $end;
$a['time_taken'] = $taken;
$a['time_start'] = $start;
$a['time_end'] = $end;
$a['time_taken'] = $taken;
return $a;
}
return $a;
}
}

View File

@ -29,58 +29,58 @@
class Log
{
// request logger object
public $request = NULL;
// request logger object
public $request = NULL;
private $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',
);
private $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',
);
private $fields = array();
private $fields = array();
public function __construct ($name = 'ykval')
{
$this->name = $name;
public function __construct ($name = 'ykval')
{
$this->name = $name;
openlog('ykval', LOG_PID, LOG_LOCAL0);
}
openlog('ykval', LOG_PID, LOG_LOCAL0);
}
public function addField ($name, $value)
{
$this->fields[$name] = $value;
}
public function addField ($name, $value)
{
$this->fields[$name] = $value;
}
public function log ($priority, $message, $extra = NULL)
{
$prefix = '';
foreach ($this->fields as $val)
$prefix .= "[$val] ";
public function log ($priority, $message, $extra = NULL)
{
$prefix = '';
foreach ($this->fields as $val)
$prefix .= "[$val] ";
$suffix = '';
if (is_array($extra)) {
foreach($extra as $key => $value) {
if (is_array($value)) {
$value = implode(':', $value);
}
$suffix .= " $key=$value ";
}
}
$suffix = '';
if (is_array($extra)) {
foreach($extra as $key => $value) {
if (is_array($value)) {
$value = implode(':', $value);
}
$suffix .= " $key=$value ";
}
}
$message = $prefix . $message . $suffix;
$message = $prefix . $message . $suffix;
$message = implode(':', array(
$this->log_levels[$priority],
$this->name,
$message
));
$message = implode(':', array(
$this->log_levels[$priority],
$this->name,
$message
));
syslog($priority, $message);
}
syslog($priority, $message);
}
}

View File

@ -1,6 +1,5 @@
#!/usr/bin/php
<?php
# Copyright (c) 2010-2015 Yubico AB
# All rights reserved.
#
@ -29,9 +28,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set_include_path(implode(PATH_SEPARATOR, array(
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
)));
require_once 'ykval-config.php';
@ -43,48 +42,48 @@ $urls = otp2ksmurls('ccccccccfnkjtvvijktfrvvginedlbvudjhjnggndtck', 16);
if (($endpoints = endpoints($urls)) === FALSE)
{
echo "Cannot parse URLs from ksm url list\n";
exit(1);
echo "Cannot parse URLs from ksm url list\n";
exit(1);
}
if ($argc == 2 && strcmp($argv[1], 'autoconf') == 0)
{
echo "yes\n";
exit(0);
echo "yes\n";
exit(0);
}
if ($argc == 2 && strcmp($argv[1], 'config') == 0)
{
echo "multigraph ykval_ksmlatency\n";
echo "graph_title KSM latency\n";
echo "graph_vlabel Average KSM Decrypt Latency (seconds)\n";
echo "graph_category ykval\n";
echo "graph_width 400\n";
echo "multigraph ykval_ksmlatency\n";
echo "graph_title KSM latency\n";
echo "graph_vlabel Average KSM Decrypt Latency (seconds)\n";
echo "graph_category ykval\n";
echo "graph_width 400\n";
foreach ($endpoints as $endpoint)
{
list ($internal, $label, $url) = $endpoint;
foreach ($endpoints as $endpoint)
{
list ($internal, $label, $url) = $endpoint;
echo "${internal}_avgwait.label ${label}\n";
echo "${internal}_avgwait.type GAUGE\n";
echo "${internal}_avgwait.info Average wait time for KSM decrypt\n";
echo "${internal}_avgwait.min 0\n";
echo "${internal}_avgwait.draw LINE1\n";
}
echo "${internal}_avgwait.label ${label}\n";
echo "${internal}_avgwait.type GAUGE\n";
echo "${internal}_avgwait.info Average wait time for KSM decrypt\n";
echo "${internal}_avgwait.min 0\n";
echo "${internal}_avgwait.draw LINE1\n";
}
exit(0);
exit(0);
}
echo "multigraph ykval_ksmlatency\n";
foreach ($endpoints as $endpoint)
{
list ($internal, $label, $url) = $endpoint;
list ($internal, $label, $url) = $endpoint;
if (($total_time = total_time($url)) === FALSE)
$total_time = 'error';
if (($total_time = total_time($url)) === FALSE)
$total_time = 'error';
echo "${internal}_avgwait.value ${total_time}\n";
echo "${internal}_avgwait.value ${total_time}\n";
}
exit(0);

View File

@ -29,52 +29,51 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set_include_path(implode(PATH_SEPARATOR, array(
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
)));
require_once 'ykval-config.php';
require_once 'ykval-common.php';
require_once 'ykval-synclib.php';
$urls = $baseParams['__YKVAL_SYNC_POOL__'];
if ($argc == 2 && strcmp($argv[1], 'autoconf') == 0)
{
if (is_array($urls) && count($urls) > 0)
{
echo "yes\n";
exit(0);
}
if (is_array($urls) && count($urls) > 0)
{
echo "yes\n";
exit(0);
}
echo "no (sync pool not configured)\n";
exit(0);
echo "no (sync pool not configured)\n";
exit(0);
}
if (($endpoints = endpoints($urls)) === FALSE)
{
echo "Cannot parse URLs from sync pool list\n";
exit(1);
echo "Cannot parse URLs from sync pool list\n";
exit(1);
}
if ($argc == 2 && strcmp($argv[1], 'config') == 0)
{
echo "graph_title YK-VAL queue size\n";
echo "graph_vlabel sync requests in queue\n";
echo "graph_category ykval\n";
echo "graph_title YK-VAL queue size\n";
echo "graph_vlabel sync requests in queue\n";
echo "graph_category ykval\n";
foreach ($endpoints as $endpoint)
{
list ($internal, $label, $url) = $endpoint;
foreach ($endpoints as $endpoint)
{
list ($internal, $label, $url) = $endpoint;
echo "${internal}_queuelength.label sync ${label}\n";
echo "${internal}_queuelength.draw AREASTACK\n";
echo "${internal}_queuelength.type GAUGE\n";
}
echo "${internal}_queuelength.label sync ${label}\n";
echo "${internal}_queuelength.draw AREASTACK\n";
echo "${internal}_queuelength.type GAUGE\n";
}
exit(0);
exit(0);
}
$sync = new SyncLib('ykval-synclib:munin');
@ -82,14 +81,14 @@ $queuelength = $sync->getQueueLengthByServer();
foreach ($endpoints as $endpoint)
{
list ($internal, $label, $url) = $endpoint;
list ($internal, $label, $url) = $endpoint;
$count = 0;
$count = 0;
if (array_key_exists($url, $queuelength))
$count = $queuelength[$url];
if (array_key_exists($url, $queuelength))
$count = $queuelength[$url];
echo "${internal}_queuelength.value $count\n";
echo "${internal}_queuelength.value $count\n";
}
exit(0);

View File

@ -29,67 +29,66 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set_include_path(implode(PATH_SEPARATOR, array(
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
)));
require_once 'ykval-config.php';
require_once 'ykval-common.php';
$urls = $baseParams['__YKVAL_SYNC_POOL__'];
if ($argc == 2 && strcmp($argv[1], 'autoconf') == 0)
{
if (is_array($urls) && count($urls) > 0)
{
echo "yes\n";
exit(0);
}
if (is_array($urls) && count($urls) > 0)
{
echo "yes\n";
exit(0);
}
echo "no (sync pool not configured)\n";
exit(0);
echo "no (sync pool not configured)\n";
exit(0);
}
if (($endpoints = endpoints($urls)) === FALSE)
{
echo "Cannot parse URLs from sync pool list\n";
exit(1);
echo "Cannot parse URLs from sync pool list\n";
exit(1);
}
if ($argc == 2 && strcmp($argv[1], 'config') == 0)
{
echo "multigraph ykval_vallatency\n";
echo "graph_title VAL latency\n";
echo "graph_vlabel Average VAL Latency (seconds)\n";
echo "graph_category ykval\n";
echo "graph_width 400\n";
echo "multigraph ykval_vallatency\n";
echo "graph_title VAL latency\n";
echo "graph_vlabel Average VAL Latency (seconds)\n";
echo "graph_category ykval\n";
echo "graph_width 400\n";
foreach ($endpoints as $endpoint)
{
list($internal, $label, $url) = $endpoint;
foreach ($endpoints as $endpoint)
{
list($internal, $label, $url) = $endpoint;
echo "${internal}_avgwait.label ${label}\n";
echo "${internal}_avgwait.type GAUGE\n";
echo "${internal}_avgwait.info Average VAL round-trip latency\n";
echo "${internal}_avgwait.min 0\n";
echo "${internal}_avgwait.draw LINE1\n";
}
echo "${internal}_avgwait.label ${label}\n";
echo "${internal}_avgwait.type GAUGE\n";
echo "${internal}_avgwait.info Average VAL round-trip latency\n";
echo "${internal}_avgwait.min 0\n";
echo "${internal}_avgwait.draw LINE1\n";
}
exit(0);
exit(0);
}
echo "multigraph ykval_vallatency\n";
foreach ($endpoints as $endpoint)
{
list ($internal, $label, $url) = $endpoint;
list ($internal, $label, $url) = $endpoint;
if (($total_time = total_time($url)) === FALSE)
$total_time = 'error';
if (($total_time = total_time($url)) === FALSE)
$total_time = 'error';
echo "${internal}_avgwait.value ${total_time}\n";
echo "${internal}_avgwait.value ${total_time}\n";
}
exit(0);

View File

@ -29,9 +29,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set_include_path(implode(PATH_SEPARATOR, array(
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
)));
require_once 'ykval-config.php';
@ -39,62 +39,62 @@ require_once 'ykval-db.php';
if ($argc == 2 && strcmp($argv[1], "autoconf") == 0)
{
print "yes\n";
exit(0);
print "yes\n";
exit(0);
}
if ($argc == 2 && strcmp($argv[1], "config") == 0)
{
echo "graph_title YK-VAL YubiKey stats\n";
echo "graph_vlabel Known YubiKeys\n";
echo "graph_category ykval\n";
echo "graph_title YK-VAL YubiKey stats\n";
echo "graph_vlabel Known YubiKeys\n";
echo "graph_category ykval\n";
echo "yubikeys_enabled.label Enabled YubiKeys\n";
echo "yubikeys_enabled.draw AREA\n";
echo "yubikeys_enabled.label Enabled YubiKeys\n";
echo "yubikeys_enabled.draw AREA\n";
echo "yubikeys_disabled.label Disabled YubiKeys\n";
echo "yubikeys_disabled.draw STACK\n";
echo "yubikeys_disabled.label Disabled YubiKeys\n";
echo "yubikeys_disabled.draw STACK\n";
echo "yubikeys_1month.label YubiKeys seen last month\n";
echo "yubikeys_1month.draw LINE2\n";
echo "yubikeys_1month.label YubiKeys seen last month\n";
echo "yubikeys_1month.draw LINE2\n";
echo "clients_enabled.label Enabled validation clients\n";
echo "clients_enabled.draw LINE2\n";
echo "clients_enabled.label Enabled validation clients\n";
echo "clients_enabled.draw LINE2\n";
echo "clients_disabled.label Disabled validation clients\n";
echo "clients_disabled.draw LINE2\n";
echo "clients_disabled.label Disabled validation clients\n";
echo "clients_disabled.draw LINE2\n";
exit(0);
exit(0);
}
$db = Db::GetDatabaseHandle($baseParams, 'ykval-munin-yubikeystats');
if (!$db->connect())
logdie($myLog, 'ERROR Database connect error (1)');
logdie($myLog, 'ERROR Database connect error (1)');
function get_count($db, $table, $conditions)
{
$res = $db->customQuery("SELECT count(1) as count FROM $table WHERE $conditions");
$res = $db->customQuery("SELECT count(1) as count FROM $table WHERE $conditions");
if ($res)
{
$r = $res->fetch(PDO::FETCH_ASSOC);
return $r['count'];
}
if ($res)
{
$r = $res->fetch(PDO::FETCH_ASSOC);
return $r['count'];
}
return Null;
return Null;
}
if ($count = get_count($db, 'yubikeys', 'active=true'))
echo "yubikeys_enabled.value $count\n";
echo "yubikeys_enabled.value $count\n";
if ($count = get_count($db, 'yubikeys', 'active=false'))
echo "yubikeys_disabled.value $count\n";
echo "yubikeys_disabled.value $count\n";
if ($count = get_count($db, 'yubikeys', 'modified >= ' . (time() - (31 * 86400))))
echo "yubikeys_1month.value $count\n";
echo "yubikeys_1month.value $count\n";
if ($count = get_count($db, 'clients', 'active=true'))
echo "clients_enabled.value $count\n";
echo "clients_enabled.value $count\n";
if ($count = get_count($db, 'clients', 'active=false'))
echo "clients_disabled.value $count\n";
echo "clients_disabled.value $count\n";

View File

@ -29,9 +29,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set_include_path(implode(PATH_SEPARATOR, array(
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
get_include_path(),
'/usr/share/yubikey-val',
'/etc/yubico/val',
)));
require_once 'ykval-synclib.php';
@ -39,8 +39,8 @@ require_once 'ykval-config.php';
require_once 'ykval-log.php';
if ($argc != 3) {
print "warning and critical levels have to be given on commandline\n";
exit (3);
print "warning and critical levels have to be given on commandline\n";
exit (3);
}
$warning = $argv[1];
@ -53,12 +53,12 @@ $len = $sync->getQueueLength ();
$message = "Queue length is $len";
if($len > $critical) {
print("CRITICAL: $message\n");
exit (2);
print("CRITICAL: $message\n");
exit (2);
} elseif($len > $warning) {
print("WARNING: $message\n");
exit (1);
print("WARNING: $message\n");
exit (1);
} else {
print("OK: $message\n");
exit (0);
print("OK: $message\n");
exit (0);
}

View File

@ -56,7 +56,7 @@ if ($sl->getNumberOfServers() === 0 && $sl->getQueueLength() === 0)
do {
$start = time();
$sl->reSync($baseParams['__YKVAL_SYNC_OLD_LIMIT__'],
$baseParams['__YKVAL_SYNC_RESYNC_TIMEOUT__']);
$baseParams['__YKVAL_SYNC_RESYNC_TIMEOUT__']);
$duration = time() - $start;
$sleep_time = max($baseParams['__YKVAL_SYNC_INTERVAL__'] - $duration, 0);
} while(sleep($sleep_time)==0);

View File

@ -39,39 +39,39 @@ $myLog = new Log('ykval-resync');
$myLog->addField('ip', $_SERVER['REMOTE_ADDR']);
if (!in_array ($_SERVER["REMOTE_ADDR"], $baseParams['__YKRESYNC_IPS__'])) {
logdie($myLog, "ERROR Authorization failed (logged ". $_SERVER["REMOTE_ADDR"] .")");
logdie($myLog, "ERROR Authorization failed (logged ". $_SERVER["REMOTE_ADDR"] .")");
}
# Parse input
$yk = $_REQUEST["yk"];
if (!$yk) {
logdie($myLog, "ERROR Missing parameter");
logdie($myLog, "ERROR Missing parameter");
}
if (!($yk == "all" || is_pubid($yk))) {
logdie($myLog, "ERROR Unknown yk value: $yk");
logdie($myLog, "ERROR Unknown yk value: $yk");
}
$myLog->addField('yk', $yk);
# Connect to db
$db = Db::GetDatabaseHandle($baseParams, 'ykval-resync');
if (!$db->connect()) {
logdie($myLog, 'ERROR Database connect error (1)');
logdie($myLog, 'ERROR Database connect error (1)');
}
if($yk == "all") {
# Get all keys
$res = $db->customQuery("SELECT yk_publicname FROM yubikeys WHERE active = true");
while($r = $db->fetchArray($res)) {
$yubikeys[] = $r['yk_publicname'];
}
$db->closeCursor($res);
# Get all keys
$res = $db->customQuery("SELECT yk_publicname FROM yubikeys WHERE active = true");
while($r = $db->fetchArray($res)) {
$yubikeys[] = $r['yk_publicname'];
}
$db->closeCursor($res);
} else {
# Check if key exists
$r = $db->findBy('yubikeys', 'yk_publicname', $yk, 1);
if (!$r) {
logdie($myLog, "ERROR Unknown yubikey: $yk");
}
$yubikeys = array($yk);
# Check if key exists
$r = $db->findBy('yubikeys', 'yk_publicname', $yk, 1);
if (!$r) {
logdie($myLog, "ERROR Unknown yubikey: $yk");
}
$yubikeys = array($yk);
}
/* Initialize the sync library. */
@ -80,21 +80,21 @@ $sync->addField('ip', $_SERVER['REMOTE_ADDR']);
$sync->addField('yk', $yk);
if (! $sync->isConnected()) {
logdie($myLog, 'ERROR Database connect error (2)');
logdie($myLog, 'ERROR Database connect error (2)');
}
foreach($yubikeys as $key) {
if (($localParams = $sync->getLocalParams($key)) === FALSE) {
logdie($myLog, 'ERROR Invalid Yubikey ' . $key);
}
if (($localParams = $sync->getLocalParams($key)) === FALSE) {
logdie($myLog, 'ERROR Invalid Yubikey ' . $key);
}
$localParams['otp'] = $key . str_repeat('c', 32); // Fake an OTP, only used for logging.
$myLog->log(LOG_DEBUG, "Auth data:", $localParams);
$localParams['otp'] = $key . str_repeat('c', 32); // Fake an OTP, only used for logging.
$myLog->log(LOG_DEBUG, "Auth data:", $localParams);
/* Queue sync request */
if (!$sync->queue($localParams, $localParams)) {
logdie($myLog, 'ERROR Failed resync');
}
/* Queue sync request */
if (!$sync->queue($localParams, $localParams)) {
logdie($myLog, 'ERROR Failed resync');
}
}
# We are done

View File

@ -38,38 +38,38 @@ $myLog = new Log('ykval-revoke');
$myLog->addField('ip', $_SERVER['REMOTE_ADDR']);
if (!in_array ($_SERVER["REMOTE_ADDR"], $baseParams['__YKREV_IPS__'])) {
logdie($myLog, "ERROR Authorization failed (logged ". $_SERVER["REMOTE_ADDR"] .")");
logdie($myLog, "ERROR Authorization failed (logged ". $_SERVER["REMOTE_ADDR"] .")");
}
# Parse input
$yk = $_REQUEST["yk"];
$do = $_REQUEST["do"];
if (!$yk || !$do) {
logdie($myLog, "ERROR Missing parameter");
logdie($myLog, "ERROR Missing parameter");
}
if (!is_pubid($yk)) {
logdie($myLog, "ERROR Unknown yk value: $yk");
logdie($myLog, "ERROR Unknown yk value: $yk");
}
if ($do != "enable" && $do != "disable") {
logdie($myLog, "ERROR Unknown do value: $do");
logdie($myLog, "ERROR Unknown do value: $do");
}
# Connect to db
$db = Db::GetDatabaseHandle($baseParams, 'ykval-revoke');
if (!$db->connect()) {
logdie($myLog, "ERROR Database connect error");
logdie($myLog, "ERROR Database connect error");
}
# Check if key exists
$r = $db->findBy('yubikeys', 'yk_publicname', $yk, 1);
if (!$r) {
logdie($myLog, "ERROR Unknown yubikey: $yk");
logdie($myLog, "ERROR Unknown yubikey: $yk");
}
# Enable/Disable the yubikey
if (!$db->updateBy('yubikeys', 'yk_publicname', $yk,
array('active'=>($do == "enable" ? "1" : "0")))) {
logdie($myLog, "ERROR Could not $do for $yk");
array('active'=>($do == "enable" ? "1" : "0")))) {
logdie($myLog, "ERROR Could not $do for $yk");
}
# We are done

View File

@ -43,43 +43,43 @@ $myLog->log(LOG_DEBUG, "Received request from $ipaddr");
if (empty($_SERVER['QUERY_STRING']))
{
sendResp(S_MISSING_PARAMETER, $myLog);
sendResp(S_MISSING_PARAMETER, $myLog);
}
// verify request sent by whitelisted address
if (in_array($ipaddr, $allowed, TRUE) === FALSE)
{
$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);
$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);
}
// define requirements on protocol
$syncParams = array(
'modified' => NULL,
'otp' => NULL,
'nonce' => NULL,
'yk_publicname' => NULL,
'yk_counter' => NULL,
'yk_use' => NULL,
'yk_high' => NULL,
'yk_low' => NULL
'modified' => NULL,
'otp' => NULL,
'nonce' => NULL,
'yk_publicname' => NULL,
'yk_counter' => NULL,
'yk_use' => NULL,
'yk_high' => NULL,
'yk_low' => NULL
);
// extract values from HTTP request
$tmp_log = 'Received ';
foreach ($syncParams as $param => $value)
{
$value = getHttpVal($param, NULL, $_GET);
$value = getHttpVal($param, NULL, $_GET);
if ($value == NULL)
{
$myLog->log(LOG_NOTICE, "Received request with parameter[s] ($param) missing value");
sendResp(S_MISSING_PARAMETER, $myLog);
}
if ($value == NULL)
{
$myLog->log(LOG_NOTICE, "Received request with parameter[s] ($param) missing value");
sendResp(S_MISSING_PARAMETER, $myLog);
}
$syncParams[$param] = $value;
$tmp_log .= "$param=$value ";
$syncParams[$param] = $value;
$tmp_log .= "$param=$value ";
}
$myLog->log(LOG_INFO, $tmp_log);
@ -89,7 +89,7 @@ $sync->addField('ip', $ipaddr);
if (! $sync->isConnected())
{
sendResp(S_BACKEND_ERROR, $myLog);
sendResp(S_BACKEND_ERROR, $myLog);
}
// at this point we should have the otp so let's add it to the logging module
@ -98,34 +98,34 @@ $myLog->addField('otp', $syncParams['otp']);
// Verify correctness of numeric input parameters
foreach (array('modified','yk_counter', 'yk_use', 'yk_high', 'yk_low') as $param)
{
// -1 is valid except for modified
if ($param !== 'modified' && $syncParams[$param] === '-1')
continue;
// -1 is valid except for modified
if ($param !== 'modified' && $syncParams[$param] === '-1')
continue;
// [0-9]+
if ($syncParams[$param] !== '' && ctype_digit($syncParams[$param]))
continue;
// [0-9]+
if ($syncParams[$param] !== '' && ctype_digit($syncParams[$param]))
continue;
$myLog->log(LOG_NOTICE, "Input parameters $param not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
$myLog->log(LOG_NOTICE, "Input parameters $param not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
}
// Verify correctness of OTP input
if (!is_otp($syncParams['otp'])) {
$myLog->log(LOG_NOTICE, "Input parameter " . $syncParams['otp'] . " not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
$myLog->log(LOG_NOTICE, "Input parameter " . $syncParams['otp'] . " not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
}
// Verify correctness of pubid input
if (!is_pubid($syncParams['yk_publicname'])) {
$myLog->log(LOG_NOTICE, "Input parameter " . $syncParams['yk_publicname'] . " not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
$myLog->log(LOG_NOTICE, "Input parameter " . $syncParams['yk_publicname'] . " not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
}
// Verify correctness of nonce input
if (!is_nonce($syncParams['nonce'])) {
$myLog->log(LOG_NOTICE, "Input parameter " . $syncParams['nonce'] . " not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
$myLog->log(LOG_NOTICE, "Input parameter " . $syncParams['nonce'] . " not correct");
sendResp(S_MISSING_PARAMETER, $myLog);
}
// get local counter data
@ -133,8 +133,8 @@ $sync->addField('otp', $syncParams['otp']);
$yk_publicname = $syncParams['yk_publicname'];
if (($localParams = $sync->getLocalParams($yk_publicname)) === FALSE)
{
$myLog->log(LOG_NOTICE, "Invalid Yubikey $yk_publicname");
sendResp(S_BACKEND_ERROR, $myLog);
$myLog->log(LOG_NOTICE, "Invalid Yubikey $yk_publicname");
sendResp(S_BACKEND_ERROR, $myLog);
}
// conditional update local database
@ -145,60 +145,60 @@ $myLog->log(LOG_DEBUG, 'Sync request params ', $syncParams);
if ($sync->countersHigherThan($localParams, $syncParams))
{
$myLog->log(LOG_WARNING, 'Remote server out of sync.');
$myLog->log(LOG_WARNING, 'Remote server out of sync.');
}
if ($sync->countersEqual($localParams, $syncParams))
{
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'])
{
/**
* 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 ($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 ($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');
}
if ($syncParams['nonce'] != $localParams['nonce'])
{
$myLog->log(LOG_WARNING, 'Remote server has received a request to validate an already validated OTP');
}
}
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!!!");
sendResp(S_BAD_OTP, $myLog);
/**
* 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);
}
$extra = array(
'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']
'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']
);
sendResp(S_OK, $myLog, '', $extra);

View File

@ -29,23 +29,23 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if($argc != 3 || !( $argv[2] == 'all' || preg_match('/^[cbdefghijklnrtuv]{0,16}$/', $argv[2]))) {
echo "Usage: ".$argv[0]." URL KEY\n\n";
echo "URL: URL of resync service.\n\n";
echo "KEY: Public identifier of a YubiKey to sync, or \"all\".\n\n";
echo "Usage example:\n\n";
echo $argv[0]." http://example.com/wsapi/2.0/resync ccccccccccdn\n";
exit(1);
echo "Usage: ".$argv[0]." URL KEY\n\n";
echo "URL: URL of resync service.\n\n";
echo "KEY: Public identifier of a YubiKey to sync, or \"all\".\n\n";
echo "Usage example:\n\n";
echo $argv[0]." http://example.com/wsapi/2.0/resync ccccccccccdn\n";
exit(1);
}
$host = $argv[1];
$yk = $argv[2];
if(!preg_match('~^https?://~', $host)) {
#Allow just an IP or host
if(strpos($host, "/") == False) {
$host = $host."/wsapi/2.0/resync";
}
$host = "http://".$host;
#Allow just an IP or host
if(strpos($host, "/") == False) {
$host = $host."/wsapi/2.0/resync";
}
$host = "http://".$host;
}
$url = $host."?yk=".$yk;
@ -59,7 +59,7 @@ curl_setopt($ch, CURLOPT_FAILONERROR, true);
$response = curl_exec($ch);
if($response == False) {
die("error");
die("error");
}
echo $response;

View File

@ -33,651 +33,651 @@ require_once 'ykval-db.php';
require_once 'ykval-log.php';
function _get($arr, $key) {
return array_key_exists($key, $arr) ? $arr[$key] : "?";
return array_key_exists($key, $arr) ? $arr[$key] : "?";
}
class SyncLib
{
public $syncServers = array();
public $dbConn = null;
public $curlopts = array();
public function __construct($logname='ykval-synclib')
{
$this->myLog = new Log($logname);
global $baseParams;
$this->syncServers = $baseParams['__YKVAL_SYNC_POOL__'];
$this->db = Db::GetDatabaseHandle($baseParams, $logname);
$this->isConnected=$this->db->connect();
$this->server_nonce=md5(uniqid(rand()));
if (array_key_exists('__YKVAL_SYNC_CURL_OPTS__', $baseParams))
{
$this->curlopts = $baseParams['__YKVAL_SYNC_CURL_OPTS__'];
}
}
public function addField($name, $value)
{
$this->myLog->addField($name, $value);
$this->db->addField($name, $value);
}
public function isConnected()
{
return $this->isConnected;
}
public function getNumberOfServers()
{
return count($this->syncServers);
}
public function getNumberOfValidAnswers()
{
if (isset($this->valid_answers))
return $this->valid_answers;
return 0;
}
public function getNumberOfAnswers()
{
if (isset($this->answers))
return $this->answers;
return 0;
}
public function getClientData($client)
{
$res = $this->db->customQuery("SELECT id, secret FROM clients WHERE active='1' AND id='" . $client . "'");
$r = $this->db->fetchArray($res);
$this->db->closeCursor($res);
if ($r)
return $r;
return false;
}
public function getQueueLength()
{
return count($this->db->findBy('queue', null, null, null));
}
public function getQueueLengthByServer()
{
$counters = array();
foreach ($this->syncServers as $server)
{
$counters[$server] = 0;
}
$result = $this->db->customQuery('SELECT server, COUNT(server) as count FROM queue GROUP BY server');
while ($row = $this->db->fetchArray($result))
{
$counters[$row['server']] = $row['count'];
}
$this->db->closeCursor($result);
return $counters;
}
public function queue($otpParams, $localParams)
{
$info = $this->createInfoString($otpParams, $localParams);
$this->otpParams = $otpParams;
$this->localParams = $localParams;
$queued = time();
$result = true;
foreach ($this->syncServers as $server)
{
$arr = array(
'queued' => $queued,
'modified' => $otpParams['modified'],
'otp' => $otpParams['otp'],
'server' => $server,
'server_nonce' => $this->server_nonce,
'info' => $info
);
if (! $this->db->save('queue', $arr))
$result = false;
}
return $result;
}
public function log($priority, $msg, $params=NULL)
{
if ($params)
$msg .= ' modified=' . _get($params, 'modified') .
' nonce=' . _get($params, 'nonce') .
' yk_publicname=' . _get($params, 'yk_publicname') .
' yk_counter=' . _get($params, 'yk_counter') .
' yk_use=' . _get($params, 'yk_use') .
' yk_high=' . _get($params, 'yk_high') .
' yk_low=' . _get($params, 'yk_low');
if ($this->myLog)
$this->myLog->log($priority, $msg);
else
error_log("Warning: myLog uninitialized in ykval-synclib.php. Message is " . $msg);
}
public function getLocalParams($yk_publicname)
{
$this->log(LOG_DEBUG, "searching for yk_publicname $yk_publicname in local db");
$res = $this->db->findBy('yubikeys', 'yk_publicname', $yk_publicname, 1);
if (!$res)
{
$this->log(LOG_NOTICE, "Discovered new identity $yk_publicname");
$this->db->save('yubikeys', array(
'active' => 1,
'created' => time(),
'modified' => -1,
'yk_publicname' => $yk_publicname,
'yk_counter' => -1,
'yk_use' => -1,
'yk_low' => -1,
'yk_high' => -1,
'nonce' => '0000000000000000',
'notes' => ''
));
$res = $this->db->findBy('yubikeys', 'yk_publicname', $yk_publicname, 1);
}
if ($res)
{
$localParams = array(
'modified' => $res['modified'],
'nonce' => $res['nonce'],
'active' => $res['active'],
'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(LOG_INFO, "yubikey found in db ", $localParams);
return $localParams;
}
$this->log(LOG_NOTICE, "params for yk_publicname $yk_publicname not found in database");
return false;
}
public function updateDbCounters($params)
{
if (!isset($params['yk_publicname']))
return false;
$arr = 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 = '('.$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'], $arr, $condition))
{
$this->log(LOG_CRIT, 'failed to update internal DB with new counters');
return false;
}
if ($this->db->rowCount() > 0)
$this->log(LOG_INFO, 'updated database ', $params);
else
$this->log(LOG_INFO, 'database not updated', $params);
return true;
}
public function countersHigherThan($p1, $p2)
{
if ($p1['yk_counter'] > $p2['yk_counter'])
return true;
if ($p1['yk_counter'] == $p2['yk_counter'] && $p1['yk_use'] > $p2['yk_use'])
return true;
return false;
}
public function countersHigherThanOrEqual($p1, $p2)
{
if ($p1['yk_counter'] > $p2['yk_counter'])
return true;
if ($p1['yk_counter'] == $p2['yk_counter'] && $p1['yk_use'] >= $p2['yk_use'])
return true;
return false;
}
public function countersEqual($p1, $p2)
{
return ($p1['yk_counter'] == $p2['yk_counter'] && $p1['yk_use'] == $p2['yk_use']);
}
// queue daemon
public function reSync($older_than, $timeout)
{
$this->log(LOG_DEBUG, 'starting resync');
/* Loop over all unique servers in queue */
$queued_limit = time()-$older_than;
$server_res = $this->db->customQuery("select distinct server from queue WHERE queued < " . $queued_limit . " or queued is null");
$server_list = array();
$mh = curl_multi_init();
$ch = array();
$entries = array();
$handles = 0;
$num_per_server = 4;
$curlopts = $this->curlopts;
while ($my_server = $this->db->fetchArray($server_res))
{
$server = $my_server['server'];
$this->log(LOG_DEBUG, "Processing queue for server " . $server);
$res = $this->db->customQuery("select * from queue WHERE (queued < " . $queued_limit . " or queued is null) and server='" . $server . "' LIMIT 1000");
$list = array();
while ($entry = $this->db->fetchArray($res))
{
$list[] = $entry;
}
$server_list[$server] = $list;
$this->db->closeCursor($res);
}
$this->db->closeCursor($server_res);
/* add up to n entries for each server we're going to sync */
foreach ($server_list as $server) {
$items = array_slice($server, 0, $num_per_server);
$counter = 0;
foreach ($items as $entry) {
$label = "{$entry['server']}:$counter";
$handle = curl_init();
$ch[$label] = $handle;
$counter++;
$this->log(LOG_INFO, "server=" . $entry['server'] . ", server_nonce=" . $entry['server_nonce'] . ", info=" . $entry['info']);
$url = $this->buildSyncUrl($entry);
$curlopts[CURLOPT_PRIVATE] = $label;
curl_settings($this, 'YK-VAL resync', $handle, $url, $timeout, $curlopts);
$entries[$label] = $entry;
curl_multi_add_handle($mh, $handle);
$handles++;
}
$empty = array();
array_splice($server, 0, $num_per_server, $empty);
if(count($server) == 0) {
unset($server_list[$entry['server']]);
}
}
while($handles > 0) {
while (curl_multi_exec($mh, $active) == CURLM_CALL_MULTI_PERFORM);
while ($info = curl_multi_info_read($mh)) {
$handle = $info['handle'];
$server = strtok(curl_getinfo($handle, CURLINFO_EFFECTIVE_URL), "?");
$label = curl_getinfo($handle, CURLINFO_PRIVATE);
$entry = $entries[$label];
$this->log(LOG_DEBUG, "handle indicated to be for $server.");
curl_multi_remove_handle($mh, $handle);
$handles--;
if ($info['result'] === CURLE_OK) {
$response = curl_multi_getcontent($handle);
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 */
/* This is the counter values we had in our database *before* processing the current OTP. */
$validationParams = $this->localParamsFromInfoString($entry['info']);
/* This is the data from the current OTP. */
$otpParams = $this->otpParamsFromInfoString($entry['info']);
/* Fetch current information from our database */
$localParams = $this->getLocalParams($otpParams['yk_publicname']);
$this->log(LOG_DEBUG, 'validation params: ', $validationParams);
$this->log(LOG_DEBUG, 'OTP params: ', $otpParams);
/* 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))
{
if ($this->countersEqual($resParams, $otpParams))
{
$this->log(LOG_INFO, 'Remote server had received the current counter values already. ');
}
else
{
$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_DEBUG, 'deleting queue entry with modified=' . $entry['modified'] .
' server_nonce=' . $entry['server_nonce'] .
' server=' . $entry['server']);
$this->db->deleteByMultiple('queue', array(
'modified' => $entry['modified'],
'server_nonce' => $entry['server_nonce'],
'server' => $entry['server']
));
}
else if (preg_match('/status=BAD_OTP/', $response))
{
$this->log(LOG_WARNING, 'Remote server says BAD_OTP, pointless to try again, removing from queue.');
$this->db->deleteByMultiple('queue', array(
'modified' => $entry['modified'],
'server_nonce' => $entry['server_nonce'],
'server' => $entry['server']
));
}
else
{
$this->log(LOG_ERR, 'Remote server refused our sync request. Check remote server logs.');
}
if (array_key_exists($server, $server_list)) {
$entry = array_shift($server_list[$server]);
if(count($server_list[$server]) == 0) {
$this->log(LOG_DEBUG, "All entries for $server synced.");
unset($server_list[$server]);
}
$this->log(LOG_INFO, "server=" . $entry['server'] . ", server_nonce=" . $entry['server_nonce'] . ", info=" . $entry['info']);
$url = $this->buildSyncUrl($entry);
$curlopts[CURLOPT_PRIVATE] = $label;
curl_settings($this, 'YK-VAL resync', $handle, $url, $timeout, $curlopts);
$entries[$label] = $entry;
curl_multi_add_handle($mh, $handle);
$handles++;
}
} else {
$this->log(LOG_NOTICE, 'Timeout. Stopping queue resync for server ' . $entry['server']);
unset($server_list[$server]);
}
}
}
foreach ($ch as $handle) {
curl_close($handle);
}
curl_multi_close($mh);
return true;
}
// blocks verify requests
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[] = $this->buildSyncUrl($row);
}
// send out requests
$ans_arr = retrieveURLasync('YK-VAL sync', $urls, $this->myLog, $ans_req, $match='status=OK', $returl=True, $timeout, $this->curlopts);
if ($ans_arr === FALSE)
{
$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)
{
// parse out parameters from each response
$resParams=$this->parseParamsFromMultiLineString($answer);
$this->log(LOG_DEBUG, 'local db contains ', $localParams);
$this->log(LOG_DEBUG, 'response contains ', $resParams);
$this->log(LOG_DEBUG, 'OTP contains ', $this->otpParams);
// update internal DB (conditional)
$this->updateDbCounters($resParams);
/**
* Check for warnings
*
* See https://developers.yubico.com/yubikey-val/doc/ServerReplicationProtocol.html
*
* NOTE: We use localParams for validationParams comparison since they are actually the
* 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) && $resParams['nonce'] != $localParams['nonce'])
{
$this->log(LOG_NOTICE, 'Servers out of sync. Nonce differs. ');
}
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.
* Otherwise, return false.
*/
if ($this->valid_answers == $ans_req)
return true;
return false;
}
private function createInfoString($otpParams, $localParams)
{
# FIXME &local_counter
return 'yk_publicname=' . $otpParams['yk_publicname'] .
'&yk_counter=' . $otpParams['yk_counter'] .
'&yk_use=' . $otpParams['yk_use'] .
'&yk_high=' . $otpParams['yk_high'] .
'&yk_low=' . $otpParams['yk_low'] .
'&nonce=' . $otpParams['nonce'] .
',local_counter=' . $localParams['yk_counter'] .
'&local_use=' . $localParams['yk_use'];
}
private function otpParamsFromInfoString($info)
{
$out = explode(',', $info);
parse_str($out[0], $params);
return $params;
}
private function otpPartFromInfoString($info)
{
$out = explode(',', $info);
return $out[0];
}
private function localParamsFromInfoString($info)
{
$out = explode(',', $info);
parse_str($out[1], $params);
return array(
'yk_counter' => $params['local_counter'],
'yk_use' => $params['local_use']
);
}
private function parseParamsFromMultiLineString($str)
{
$i = preg_match("/^modified=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse modified value: $str");
}
$resParams['modified']=$out[1];
$i = preg_match("/^yk_publicname=([cbdefghijklnrtuv]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse publicname value: $str");
}
$resParams['yk_publicname']=$out[1];
$i = preg_match("/^yk_counter=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse counter value: $str");
}
$resParams['yk_counter']=$out[1];
$i = preg_match("/^yk_use=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse use value: $str");
}
$resParams['yk_use']=$out[1];
$i = preg_match("/^yk_high=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse high value: $str");
}
$resParams['yk_high']=$out[1];
$i = preg_match("/^yk_low=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse low value: $str");
}
$resParams['yk_low']=$out[1];
$i = preg_match("/^nonce=([[:alnum:]]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse nonce value: $str");
}
$resParams['nonce']=$out[1];
return $resParams;
}
private function deleteQueueEntry($answer)
{
preg_match('/url=(.*)\?/', $answer, $out);
$server = $out[1];
$this->log(LOG_INFO, "deleting server=" . $server .
" modified=" . $this->otpParams['modified'] .
" server_nonce=" . $this->server_nonce);
$this->db->deleteByMultiple('queue', array(
'modified' => $this->otpParams['modified'],
'server_nonce' => $this->server_nonce,
'server' => $server
));
}
private function buildSyncUrl($entry)
{
return $entry['server'] .
"?otp=" . $entry['otp'] .
"&modified=" . $entry['modified'] .
"&" . $this->otpPartFromInfoString($entry['info']);
}
public $syncServers = array();
public $dbConn = null;
public $curlopts = array();
public function __construct($logname='ykval-synclib')
{
$this->myLog = new Log($logname);
global $baseParams;
$this->syncServers = $baseParams['__YKVAL_SYNC_POOL__'];
$this->db = Db::GetDatabaseHandle($baseParams, $logname);
$this->isConnected=$this->db->connect();
$this->server_nonce=md5(uniqid(rand()));
if (array_key_exists('__YKVAL_SYNC_CURL_OPTS__', $baseParams))
{
$this->curlopts = $baseParams['__YKVAL_SYNC_CURL_OPTS__'];
}
}
public function addField($name, $value)
{
$this->myLog->addField($name, $value);
$this->db->addField($name, $value);
}
public function isConnected()
{
return $this->isConnected;
}
public function getNumberOfServers()
{
return count($this->syncServers);
}
public function getNumberOfValidAnswers()
{
if (isset($this->valid_answers))
return $this->valid_answers;
return 0;
}
public function getNumberOfAnswers()
{
if (isset($this->answers))
return $this->answers;
return 0;
}
public function getClientData($client)
{
$res = $this->db->customQuery("SELECT id, secret FROM clients WHERE active='1' AND id='" . $client . "'");
$r = $this->db->fetchArray($res);
$this->db->closeCursor($res);
if ($r)
return $r;
return false;
}
public function getQueueLength()
{
return count($this->db->findBy('queue', null, null, null));
}
public function getQueueLengthByServer()
{
$counters = array();
foreach ($this->syncServers as $server)
{
$counters[$server] = 0;
}
$result = $this->db->customQuery('SELECT server, COUNT(server) as count FROM queue GROUP BY server');
while ($row = $this->db->fetchArray($result))
{
$counters[$row['server']] = $row['count'];
}
$this->db->closeCursor($result);
return $counters;
}
public function queue($otpParams, $localParams)
{
$info = $this->createInfoString($otpParams, $localParams);
$this->otpParams = $otpParams;
$this->localParams = $localParams;
$queued = time();
$result = true;
foreach ($this->syncServers as $server)
{
$arr = array(
'queued' => $queued,
'modified' => $otpParams['modified'],
'otp' => $otpParams['otp'],
'server' => $server,
'server_nonce' => $this->server_nonce,
'info' => $info
);
if (! $this->db->save('queue', $arr))
$result = false;
}
return $result;
}
public function log($priority, $msg, $params=NULL)
{
if ($params)
$msg .= ' modified=' . _get($params, 'modified') .
' nonce=' . _get($params, 'nonce') .
' yk_publicname=' . _get($params, 'yk_publicname') .
' yk_counter=' . _get($params, 'yk_counter') .
' yk_use=' . _get($params, 'yk_use') .
' yk_high=' . _get($params, 'yk_high') .
' yk_low=' . _get($params, 'yk_low');
if ($this->myLog)
$this->myLog->log($priority, $msg);
else
error_log("Warning: myLog uninitialized in ykval-synclib.php. Message is " . $msg);
}
public function getLocalParams($yk_publicname)
{
$this->log(LOG_DEBUG, "searching for yk_publicname $yk_publicname in local db");
$res = $this->db->findBy('yubikeys', 'yk_publicname', $yk_publicname, 1);
if (!$res)
{
$this->log(LOG_NOTICE, "Discovered new identity $yk_publicname");
$this->db->save('yubikeys', array(
'active' => 1,
'created' => time(),
'modified' => -1,
'yk_publicname' => $yk_publicname,
'yk_counter' => -1,
'yk_use' => -1,
'yk_low' => -1,
'yk_high' => -1,
'nonce' => '0000000000000000',
'notes' => ''
));
$res = $this->db->findBy('yubikeys', 'yk_publicname', $yk_publicname, 1);
}
if ($res)
{
$localParams = array(
'modified' => $res['modified'],
'nonce' => $res['nonce'],
'active' => $res['active'],
'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(LOG_INFO, "yubikey found in db ", $localParams);
return $localParams;
}
$this->log(LOG_NOTICE, "params for yk_publicname $yk_publicname not found in database");
return false;
}
public function updateDbCounters($params)
{
if (!isset($params['yk_publicname']))
return false;
$arr = 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 = '('.$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'], $arr, $condition))
{
$this->log(LOG_CRIT, 'failed to update internal DB with new counters');
return false;
}
if ($this->db->rowCount() > 0)
$this->log(LOG_INFO, 'updated database ', $params);
else
$this->log(LOG_INFO, 'database not updated', $params);
return true;
}
public function countersHigherThan($p1, $p2)
{
if ($p1['yk_counter'] > $p2['yk_counter'])
return true;
if ($p1['yk_counter'] == $p2['yk_counter'] && $p1['yk_use'] > $p2['yk_use'])
return true;
return false;
}
public function countersHigherThanOrEqual($p1, $p2)
{
if ($p1['yk_counter'] > $p2['yk_counter'])
return true;
if ($p1['yk_counter'] == $p2['yk_counter'] && $p1['yk_use'] >= $p2['yk_use'])
return true;
return false;
}
public function countersEqual($p1, $p2)
{
return ($p1['yk_counter'] == $p2['yk_counter'] && $p1['yk_use'] == $p2['yk_use']);
}
// queue daemon
public function reSync($older_than, $timeout)
{
$this->log(LOG_DEBUG, 'starting resync');
/* Loop over all unique servers in queue */
$queued_limit = time()-$older_than;
$server_res = $this->db->customQuery("select distinct server from queue WHERE queued < " . $queued_limit . " or queued is null");
$server_list = array();
$mh = curl_multi_init();
$ch = array();
$entries = array();
$handles = 0;
$num_per_server = 4;
$curlopts = $this->curlopts;
while ($my_server = $this->db->fetchArray($server_res))
{
$server = $my_server['server'];
$this->log(LOG_DEBUG, "Processing queue for server " . $server);
$res = $this->db->customQuery("select * from queue WHERE (queued < " . $queued_limit . " or queued is null) and server='" . $server . "' LIMIT 1000");
$list = array();
while ($entry = $this->db->fetchArray($res))
{
$list[] = $entry;
}
$server_list[$server] = $list;
$this->db->closeCursor($res);
}
$this->db->closeCursor($server_res);
/* add up to n entries for each server we're going to sync */
foreach ($server_list as $server) {
$items = array_slice($server, 0, $num_per_server);
$counter = 0;
foreach ($items as $entry) {
$label = "{$entry['server']}:$counter";
$handle = curl_init();
$ch[$label] = $handle;
$counter++;
$this->log(LOG_INFO, "server=" . $entry['server'] . ", server_nonce=" . $entry['server_nonce'] . ", info=" . $entry['info']);
$url = $this->buildSyncUrl($entry);
$curlopts[CURLOPT_PRIVATE] = $label;
curl_settings($this, 'YK-VAL resync', $handle, $url, $timeout, $curlopts);
$entries[$label] = $entry;
curl_multi_add_handle($mh, $handle);
$handles++;
}
$empty = array();
array_splice($server, 0, $num_per_server, $empty);
if(count($server) == 0) {
unset($server_list[$entry['server']]);
}
}
while($handles > 0) {
while (curl_multi_exec($mh, $active) == CURLM_CALL_MULTI_PERFORM);
while ($info = curl_multi_info_read($mh)) {
$handle = $info['handle'];
$server = strtok(curl_getinfo($handle, CURLINFO_EFFECTIVE_URL), "?");
$label = curl_getinfo($handle, CURLINFO_PRIVATE);
$entry = $entries[$label];
$this->log(LOG_DEBUG, "handle indicated to be for $server.");
curl_multi_remove_handle($mh, $handle);
$handles--;
if ($info['result'] === CURLE_OK) {
$response = curl_multi_getcontent($handle);
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 */
/* This is the counter values we had in our database *before* processing the current OTP. */
$validationParams = $this->localParamsFromInfoString($entry['info']);
/* This is the data from the current OTP. */
$otpParams = $this->otpParamsFromInfoString($entry['info']);
/* Fetch current information from our database */
$localParams = $this->getLocalParams($otpParams['yk_publicname']);
$this->log(LOG_DEBUG, 'validation params: ', $validationParams);
$this->log(LOG_DEBUG, 'OTP params: ', $otpParams);
/* 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))
{
if ($this->countersEqual($resParams, $otpParams))
{
$this->log(LOG_INFO, 'Remote server had received the current counter values already. ');
}
else
{
$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_DEBUG, 'deleting queue entry with modified=' . $entry['modified'] .
' server_nonce=' . $entry['server_nonce'] .
' server=' . $entry['server']);
$this->db->deleteByMultiple('queue', array(
'modified' => $entry['modified'],
'server_nonce' => $entry['server_nonce'],
'server' => $entry['server']
));
}
else if (preg_match('/status=BAD_OTP/', $response))
{
$this->log(LOG_WARNING, 'Remote server says BAD_OTP, pointless to try again, removing from queue.');
$this->db->deleteByMultiple('queue', array(
'modified' => $entry['modified'],
'server_nonce' => $entry['server_nonce'],
'server' => $entry['server']
));
}
else
{
$this->log(LOG_ERR, 'Remote server refused our sync request. Check remote server logs.');
}
if (array_key_exists($server, $server_list)) {
$entry = array_shift($server_list[$server]);
if(count($server_list[$server]) == 0) {
$this->log(LOG_DEBUG, "All entries for $server synced.");
unset($server_list[$server]);
}
$this->log(LOG_INFO, "server=" . $entry['server'] . ", server_nonce=" . $entry['server_nonce'] . ", info=" . $entry['info']);
$url = $this->buildSyncUrl($entry);
$curlopts[CURLOPT_PRIVATE] = $label;
curl_settings($this, 'YK-VAL resync', $handle, $url, $timeout, $curlopts);
$entries[$label] = $entry;
curl_multi_add_handle($mh, $handle);
$handles++;
}
} else {
$this->log(LOG_NOTICE, 'Timeout. Stopping queue resync for server ' . $entry['server']);
unset($server_list[$server]);
}
}
}
foreach ($ch as $handle) {
curl_close($handle);
}
curl_multi_close($mh);
return true;
}
// blocks verify requests
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[] = $this->buildSyncUrl($row);
}
// send out requests
$ans_arr = retrieveURLasync('YK-VAL sync', $urls, $this->myLog, $ans_req, $match='status=OK', $returl=True, $timeout, $this->curlopts);
if ($ans_arr === FALSE)
{
$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)
{
// parse out parameters from each response
$resParams=$this->parseParamsFromMultiLineString($answer);
$this->log(LOG_DEBUG, 'local db contains ', $localParams);
$this->log(LOG_DEBUG, 'response contains ', $resParams);
$this->log(LOG_DEBUG, 'OTP contains ', $this->otpParams);
// update internal DB (conditional)
$this->updateDbCounters($resParams);
/**
* Check for warnings
*
* See https://developers.yubico.com/yubikey-val/doc/ServerReplicationProtocol.html
*
* NOTE: We use localParams for validationParams comparison since they are actually the
* 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) && $resParams['nonce'] != $localParams['nonce'])
{
$this->log(LOG_NOTICE, 'Servers out of sync. Nonce differs. ');
}
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.
* Otherwise, return false.
*/
if ($this->valid_answers == $ans_req)
return true;
return false;
}
private function createInfoString($otpParams, $localParams)
{
# FIXME &local_counter
return 'yk_publicname=' . $otpParams['yk_publicname'] .
'&yk_counter=' . $otpParams['yk_counter'] .
'&yk_use=' . $otpParams['yk_use'] .
'&yk_high=' . $otpParams['yk_high'] .
'&yk_low=' . $otpParams['yk_low'] .
'&nonce=' . $otpParams['nonce'] .
',local_counter=' . $localParams['yk_counter'] .
'&local_use=' . $localParams['yk_use'];
}
private function otpParamsFromInfoString($info)
{
$out = explode(',', $info);
parse_str($out[0], $params);
return $params;
}
private function otpPartFromInfoString($info)
{
$out = explode(',', $info);
return $out[0];
}
private function localParamsFromInfoString($info)
{
$out = explode(',', $info);
parse_str($out[1], $params);
return array(
'yk_counter' => $params['local_counter'],
'yk_use' => $params['local_use']
);
}
private function parseParamsFromMultiLineString($str)
{
$i = preg_match("/^modified=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse modified value: $str");
}
$resParams['modified']=$out[1];
$i = preg_match("/^yk_publicname=([cbdefghijklnrtuv]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse publicname value: $str");
}
$resParams['yk_publicname']=$out[1];
$i = preg_match("/^yk_counter=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse counter value: $str");
}
$resParams['yk_counter']=$out[1];
$i = preg_match("/^yk_use=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse use value: $str");
}
$resParams['yk_use']=$out[1];
$i = preg_match("/^yk_high=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse high value: $str");
}
$resParams['yk_high']=$out[1];
$i = preg_match("/^yk_low=(-1|[0-9]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse low value: $str");
}
$resParams['yk_low']=$out[1];
$i = preg_match("/^nonce=([[:alnum:]]+)/m", $str, $out);
if ($i != 1) {
$this->log(LOG_ALERT, "cannot parse nonce value: $str");
}
$resParams['nonce']=$out[1];
return $resParams;
}
private function deleteQueueEntry($answer)
{
preg_match('/url=(.*)\?/', $answer, $out);
$server = $out[1];
$this->log(LOG_INFO, "deleting server=" . $server .
" modified=" . $this->otpParams['modified'] .
" server_nonce=" . $this->server_nonce);
$this->db->deleteByMultiple('queue', array(
'modified' => $this->otpParams['modified'],
'server_nonce' => $this->server_nonce,
'server' => $server
));
}
private function buildSyncUrl($entry)
{
return $entry['server'] .
"?otp=" . $entry['otp'] .
"&modified=" . $entry['modified'] .
"&" . $this->otpPartFromInfoString($entry['info']);
}
}

View File

@ -39,7 +39,7 @@ header('content-type: text/plain');
$ipaddr = $_SERVER['REMOTE_ADDR'];
$https = (array_key_exists('HTTPS', $_SERVER) === TRUE
&& strtolower($_SERVER['HTTPS']) !== 'off' ? TRUE : FALSE);
&& strtolower($_SERVER['HTTPS']) !== 'off' ? TRUE : FALSE);
$myLog = new Log('ykval-verify');
$myLog->addField('ip', $ipaddr);
@ -47,9 +47,9 @@ $myLog->addField('ip', $ipaddr);
$myLog->request = new LogVerify();
if (array_key_exists('__YKVAL_VERIFY_LOGFORMAT__', $baseParams)
&& is_string($baseParams['__YKVAL_VERIFY_LOGFORMAT__']))
&& is_string($baseParams['__YKVAL_VERIFY_LOGFORMAT__']))
{
$myLog->request->format = $baseParams['__YKVAL_VERIFY_LOGFORMAT__'];
$myLog->request->format = $baseParams['__YKVAL_VERIFY_LOGFORMAT__'];
}
$myLog->request->set('ip', $ipaddr);
@ -60,24 +60,24 @@ unset($time_start);
if ($_GET)
{
$request = $_GET;
$message = 'Request: ' . $_SERVER['QUERY_STRING'];
$request = $_GET;
$message = 'Request: ' . $_SERVER['QUERY_STRING'];
}
else if ($_POST)
{
$request = $_POST;
$kv = array();
foreach ($request as $key => $value)
{
$kv[] = "$key=$value";
}
$message = 'POST: ' . join('&', $kv);
unset($kv);
$request = $_POST;
$kv = array();
foreach ($request as $key => $value)
{
$kv[] = "$key=$value";
}
$message = 'POST: ' . join('&', $kv);
unset($kv);
}
else
{
$request = array();
$message = '';
$request = array();
$message = '';
}
$message .= ' (at ' . date('c') . ' ' . microtime() . ') HTTP' . ($https ? 'S' : '');
$myLog->log(LOG_INFO, $message);
@ -87,11 +87,11 @@ unset($message);
/* Detect protocol version */
if (preg_match('/\/wsapi\/([0-9]+)\.([0-9]+)\//', $_SERVER['REQUEST_URI'], $out))
{
$protocol_version = $out[1] + $out[2] * 0.1;
$protocol_version = $out[1] + $out[2] * 0.1;
}
else
{
$protocol_version = 1.0;
$protocol_version = 1.0;
}
$myLog->request->set('protocol', $protocol_version);
@ -108,10 +108,10 @@ $otp = getHttpVal('otp', '', $request);
$otp = strtolower($otp);
if (preg_match('/^[jxe.uidchtnbpygk]+$/', $otp))
{
$new_otp = strtr($otp, 'jxe.uidchtnbpygk', 'cbdefghijklnrtuv');
$myLog->log(LOG_INFO, "Dvorak OTP converting $otp to $new_otp");
$otp = $new_otp;
unset($new_otp);
$new_otp = strtr($otp, 'jxe.uidchtnbpygk', 'cbdefghijklnrtuv');
$myLog->log(LOG_INFO, "Dvorak OTP converting $otp to $new_otp");
$otp = $new_otp;
unset($new_otp);
}
$myLog->request->set('signed', ($h === '' ? '-' : 'signed'));
@ -126,7 +126,7 @@ $extra = array();
if ($protocol_version >= 2.0)
{
$extra['otp'] = $otp;
$extra['otp'] = $otp;
}
/**
@ -137,23 +137,23 @@ $myLog->addField('otp', $otp);
if ($protocol_version >= 2.0)
{
$sl = getHttpVal('sl', '', $request);
$timeout = getHttpVal('timeout', '', $request);
$nonce = getHttpVal('nonce', '', $request);
$sl = getHttpVal('sl', '', $request);
$timeout = getHttpVal('timeout', '', $request);
$nonce = getHttpVal('nonce', '', $request);
$myLog->request->set('sl', $sl);
$myLog->request->set('timeout', $timeout);
$myLog->request->set('nonce', $nonce);
$myLog->request->set('sl', $sl);
$myLog->request->set('timeout', $timeout);
$myLog->request->set('nonce', $nonce);
/* Nonce is required from protocol 2.0 */
if (!$nonce)
{
$myLog->log(LOG_NOTICE, 'Nonce is missing and protocol version >= 2.0');
sendResp(S_MISSING_PARAMETER, $myLog);
}
/* Nonce is required from protocol 2.0 */
if (!$nonce)
{
$myLog->log(LOG_NOTICE, 'Nonce is missing and protocol version >= 2.0');
sendResp(S_MISSING_PARAMETER, $myLog);
}
/* Add nonce to response parameters */
$extra['nonce'] = $nonce;
/* Add nonce to response parameters */
$extra['nonce'] = $nonce;
}
@ -176,10 +176,10 @@ if (isset($sl) && $sl != '') {
} else if (strcasecmp($sl, 'secure') == 0) {
$sl = $baseParams['__YKVAL_SYNC_SECURE_LEVEL__'];
} else {
$sl = intval($sl); // non-numbers return zero
if ($sl < 1) {
$myLog->log(LOG_NOTICE, 'SL is provided but not correct');
sendResp(S_MISSING_PARAMETER, $myLog);
$sl = intval($sl); // non-numbers return zero
if ($sl < 1) {
$myLog->log(LOG_NOTICE, 'SL is provided but not correct');
sendResp(S_MISSING_PARAMETER, $myLog);
}
}
} else {
@ -187,28 +187,28 @@ if (isset($sl) && $sl != '') {
}
if (!isset($timeout) || $timeout == '') {
$timeout = $baseParams['__YKVAL_SYNC_DEFAULT_TIMEOUT__'];
$timeout = $baseParams['__YKVAL_SYNC_DEFAULT_TIMEOUT__'];
} else if (!ctype_digit($timeout)) {
$myLog->log(LOG_NOTICE, 'timeout is provided but not correct');
sendResp(S_MISSING_PARAMETER, $myLog);
$myLog->log(LOG_NOTICE, 'timeout is provided but not correct');
sendResp(S_MISSING_PARAMETER, $myLog);
}
if (!is_otp($otp))
{
$myLog->log(LOG_NOTICE, "Invalid OTP: $otp");
sendResp(S_BAD_OTP, $myLog);
$myLog->log(LOG_NOTICE, "Invalid OTP: $otp");
sendResp(S_BAD_OTP, $myLog);
}
if (!is_clientid($client))
{
$myLog->log(LOG_NOTICE, 'Client ID is missing or invalid');
sendResp(S_MISSING_PARAMETER, $myLog);
$myLog->log(LOG_NOTICE, 'Client ID is missing or invalid');
sendResp(S_MISSING_PARAMETER, $myLog);
}
if (isset($nonce) && !is_nonce($nonce))
{
$myLog->log(LOG_NOTICE, 'NONCE is provided but not correct');
sendResp(S_MISSING_PARAMETER, $myLog);
$myLog->log(LOG_NOTICE, 'NONCE is provided but not correct');
sendResp(S_MISSING_PARAMETER, $myLog);
}
/**
@ -227,13 +227,13 @@ $sync->addField('otp', $otp);
if (! $sync->isConnected())
{
sendResp(S_BACKEND_ERROR, $myLog);
sendResp(S_BACKEND_ERROR, $myLog);
}
if (($cd = $sync->getClientData($client)) === FALSE)
{
$myLog->log(LOG_NOTICE, "Invalid client id $client");
sendResp(S_NO_SUCH_CLIENT, $myLog);
$myLog->log(LOG_NOTICE, "Invalid client id $client");
sendResp(S_NO_SUCH_CLIENT, $myLog);
}
$myLog->log(LOG_DEBUG, 'Client data:', $cd);
@ -247,16 +247,16 @@ unset($cd);
if ($h != '')
{
// Create the signature using the API key
unset($request['h']);
// Create the signature using the API key
unset($request['h']);
$hmac = sign($request, $apiKey, $myLog);
$hmac = sign($request, $apiKey, $myLog);
if (hash_equals($hmac, $h) === FALSE)
{
$myLog->log(LOG_DEBUG, "client hmac=$h, server hmac=$hmac");
sendResp(S_BAD_SIGNATURE, $myLog, $apiKey);
}
if (hash_equals($hmac, $h) === FALSE)
{
$myLog->log(LOG_DEBUG, "client hmac=$h, server hmac=$hmac");
sendResp(S_BAD_SIGNATURE, $myLog, $apiKey);
}
}
/**
@ -265,33 +265,33 @@ if ($h != '')
*/
if ($protocol_version < 2.0)
{
// we need to create a nonce manually here
$nonce = md5(uniqid(rand()));
$myLog->log(LOG_INFO, "protocol version below 2.0. Created nonce $nonce");
// we need to create a nonce manually here
$nonce = md5(uniqid(rand()));
$myLog->log(LOG_INFO, "protocol version below 2.0. Created nonce $nonce");
}
// which YK-KSM should we talk to?
$urls = otp2ksmurls($otp, $client);
if (!is_array($urls))
{
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
}
// decode OTP from input
$curlopts = array();
if (array_key_exists('__YKVAL_KSM_CURL_OPTS__', $baseParams))
{
$curlopts = $baseParams['__YKVAL_KSM_CURL_OPTS__'];
$curlopts = $baseParams['__YKVAL_KSM_CURL_OPTS__'];
}
if (($otpinfo = KSMdecryptOTP($urls, $myLog, $curlopts)) === FALSE)
{
/**
* FIXME
*
* Return S_BACKEND_ERROR if there are connection issues,
* e.g. misconfigured otp2ksmurls.
*/
sendResp(S_BAD_OTP, $myLog, $apiKey);
/**
* FIXME
*
* Return S_BACKEND_ERROR if there are connection issues,
* e.g. misconfigured otp2ksmurls.
*/
sendResp(S_BAD_OTP, $myLog, $apiKey);
}
$myLog->request->set('counter', $otpinfo['session_counter']);
$myLog->request->set('use', $otpinfo['session_use']);
@ -304,28 +304,28 @@ $public_id = substr($otp, 0, strlen ($otp) - TOKEN_LEN);
$myLog->request->set('public_id', $public_id);
if (($localParams = $sync->getLocalParams($public_id)) === FALSE)
{
$myLog->log(LOG_NOTICE, "Invalid Yubikey $public_id");
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
$myLog->log(LOG_NOTICE, "Invalid Yubikey $public_id");
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
}
$myLog->log(LOG_DEBUG, 'Auth data:', $localParams);
if ($localParams['active'] != 1)
{
$myLog->log(LOG_NOTICE, "De-activated Yubikey $public_id");
sendResp(S_BAD_OTP, $myLog, $apiKey);
$myLog->log(LOG_NOTICE, "De-activated Yubikey $public_id");
sendResp(S_BAD_OTP, $myLog, $apiKey);
}
/* Build OTP params */
$otpParams = array(
'modified' => time(),
'otp' => $otp,
'nonce' => $nonce,
'yk_publicname' => $public_id,
'yk_counter' => $otpinfo['session_counter'],
'yk_use' => $otpinfo['session_use'],
'yk_high' => $otpinfo['high'],
'yk_low' => $otpinfo['low']
'modified' => time(),
'otp' => $otp,
'nonce' => $nonce,
'yk_publicname' => $public_id,
'yk_counter' => $otpinfo['session_counter'],
'yk_use' => $otpinfo['session_use'],
'yk_high' => $otpinfo['high'],
'yk_low' => $otpinfo['low']
);
unset($otpinfo);
@ -333,117 +333,117 @@ unset($otpinfo);
/* First check if OTP is seen with the same nonce, in such case we have an replayed request */
if ($sync->countersEqual($localParams, $otpParams) && $localParams['nonce'] == $otpParams['nonce'])
{
$myLog->log(LOG_WARNING, 'Replayed request');
sendResp(S_REPLAYED_REQUEST, $myLog, $apiKey, $extra);
$myLog->log(LOG_WARNING, 'Replayed request');
sendResp(S_REPLAYED_REQUEST, $myLog, $apiKey, $extra);
}
/* 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);
$sync->log(LOG_WARNING, 'replayed OTP: Otp counters ', $otpParams);
sendResp(S_REPLAYED_OTP, $myLog, $apiKey, $extra);
$sync->log(LOG_WARNING, 'replayed OTP: Local counters higher');
$sync->log(LOG_WARNING, 'replayed OTP: Local counters ', $localParams);
$sync->log(LOG_WARNING, 'replayed OTP: Otp counters ', $otpParams);
sendResp(S_REPLAYED_OTP, $myLog, $apiKey, $extra);
}
/* Valid OTP, update database. */
if (!$sync->updateDbCounters($otpParams))
{
$myLog->log(LOG_CRIT, 'Failed to update yubikey counters in database');
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
$myLog->log(LOG_CRIT, 'Failed to update yubikey counters in database');
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
}
/* Queue sync requests */
if (!$sync->queue($otpParams, $localParams))
{
$myLog->log(LOG_CRIT, 'failed to queue sync requests');
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
$myLog->log(LOG_CRIT, 'failed to queue sync requests');
sendResp(S_BACKEND_ERROR, $myLog, $apiKey);
}
$nr_servers = $sync->getNumberOfServers();
$req_answers = ceil($nr_servers * $sl / 100.0);
if ($req_answers > 0)
{
$syncres = $sync->sync($req_answers, $timeout);
$nr_answers = $sync->getNumberOfAnswers();
$nr_valid_answers = $sync->getNumberOfValidAnswers();
$sl_success_rate = floor(100.0 * $nr_valid_answers / $nr_servers);
$syncres = $sync->sync($req_answers, $timeout);
$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;
$nr_valid_answers = 0;
$sl_success_rate = 0;
$syncres = true;
$nr_answers = 0;
$nr_valid_answers = 0;
$sl_success_rate = 0;
}
$myLog->log(LOG_INFO, '', array(
'synclevel' => $sl,
'nr servers' => $nr_servers,
'req answers' => $req_answers,
'answers' => $nr_answers,
'valid answers' => $nr_valid_answers,
'sl success rate' => $sl_success_rate,
'timeout' => $timeout,
'synclevel' => $sl,
'nr servers' => $nr_servers,
'req answers' => $req_answers,
'answers' => $nr_answers,
'valid answers' => $nr_valid_answers,
'sl success rate' => $sl_success_rate,
'timeout' => $timeout,
));
if ($syncres == False)
{
/* sync returned false, indicating that
either at least 1 answer marked OTP as invalid or
there were not enough answers */
$myLog->log(LOG_WARNING, 'Sync failed');
/* sync returned false, indicating that
either at least 1 answer marked OTP as invalid or
there were not enough answers */
$myLog->log(LOG_WARNING, 'Sync failed');
if ($nr_valid_answers != $nr_answers)
sendResp(S_REPLAYED_OTP, $myLog, $apiKey, $extra);
if ($nr_valid_answers != $nr_answers)
sendResp(S_REPLAYED_OTP, $myLog, $apiKey, $extra);
$extra['sl'] = $sl_success_rate;
sendResp(S_NOT_ENOUGH_ANSWERS, $myLog, $apiKey, $extra);
$extra['sl'] = $sl_success_rate;
sendResp(S_NOT_ENOUGH_ANSWERS, $myLog, $apiKey, $extra);
}
if ($otpParams['yk_counter'] == $localParams['yk_counter'] && $otpParams['yk_use'] > $localParams['yk_use'])
{
$ts = ($otpParams['yk_high'] << 16) + $otpParams['yk_low'];
$seenTs = ($localParams['yk_high'] << 16) + $localParams['yk_low'];
$tsDiff = $ts - $seenTs;
$tsDelta = $tsDiff * TS_SEC;
$ts = ($otpParams['yk_high'] << 16) + $otpParams['yk_low'];
$seenTs = ($localParams['yk_high'] << 16) + $localParams['yk_low'];
$tsDiff = $ts - $seenTs;
$tsDelta = $tsDiff * TS_SEC;
$now = time();
$elapsed = $now - $localParams['modified'];
$deviation = abs($elapsed - $tsDelta);
$now = time();
$elapsed = $now - $localParams['modified'];
$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.
if ($elapsed != 0)
{
$percent = $deviation/$elapsed;
}
else
{
$percent = 1;
}
// 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
{
$percent = 1;
}
$myLog->log(LOG_INFO, 'Timestamp', array(
'seen' => $seenTs,
'this' => $ts,
'delta' => $tsDiff,
'secs' => $tsDelta,
'accessed' => sprintf('%s (%s)', $localParams['modified'], date('Y-m-d H:i:s', $localParams['modified'])),
'now' => sprintf('%s (%s)', $now, date('Y-m-d H:i:s', $now)),
'elapsed' => $elapsed,
'deviation' => sprintf('%s secs or %s%%', $deviation, round(100 * $percent)),
));
$myLog->log(LOG_INFO, 'Timestamp', array(
'seen' => $seenTs,
'this' => $ts,
'delta' => $tsDiff,
'secs' => $tsDelta,
'accessed' => sprintf('%s (%s)', $localParams['modified'], date('Y-m-d H:i:s', $localParams['modified'])),
'now' => sprintf('%s (%s)', $now, date('Y-m-d H:i:s', $now)),
'elapsed' => $elapsed,
'deviation' => sprintf('%s secs or %s%%', $deviation, round(100 * $percent)),
));
if ($deviation > TS_ABS_TOLERANCE && $percent > TS_REL_TOLERANCE)
{
$myLog->log(LOG_NOTICE, 'OTP failed phishing test');
if ($deviation > TS_ABS_TOLERANCE && $percent > TS_REL_TOLERANCE)
{
$myLog->log(LOG_NOTICE, 'OTP failed phishing test');
// FIXME
// This was wrapped around if (0). should we nuke or enable?
// sendResp(S_DELAYED_OTP, $myLog, $apiKey, $extra);
}
// FIXME
// This was wrapped around if (0). should we nuke or enable?
// sendResp(S_DELAYED_OTP, $myLog, $apiKey, $extra);
}
}
/**
@ -452,14 +452,14 @@ if ($otpParams['yk_counter'] == $localParams['yk_counter'] && $otpParams['yk_use
if ($protocol_version >= 2.0)
{
$extra['sl'] = $sl_success_rate;
$extra['sl'] = $sl_success_rate;
}
if ($timestamp == 1)
{
$extra['timestamp'] = ($otpParams['yk_high'] << 16) + $otpParams['yk_low'];
$extra['sessioncounter'] = $otpParams['yk_counter'];
$extra['sessionuse'] = $otpParams['yk_use'];
$extra['timestamp'] = ($otpParams['yk_high'] << 16) + $otpParams['yk_low'];
$extra['sessioncounter'] = $otpParams['yk_counter'];
$extra['sessionuse'] = $otpParams['yk_use'];
}
sendResp(S_OK, $myLog, $apiKey, $extra);