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:
parent
d0e4db3245
commit
2c133de5f3
@ -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";
|
||||
|
||||
|
@ -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";
|
||||
|
||||
|
460
ykval-common.php
460
ykval-common.php
@ -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'];
|
||||
}
|
||||
|
@ -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",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
418
ykval-db-oci.php
418
ykval-db-oci.php
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
403
ykval-db-pdo.php
403
ykval-db-pdo.php
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
510
ykval-db.php
510
ykval-db.php
@ -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);
|
||||
}
|
||||
}
|
||||
|
36
ykval-export
36
ykval-export
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
120
ykval-import
120
ykval-import
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
154
ykval-sync.php
154
ykval-sync.php
@ -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);
|
||||
|
@ -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;
|
||||
|
1286
ykval-synclib.php
1286
ykval-synclib.php
@ -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']);
|
||||
}
|
||||
}
|
||||
|
310
ykval-verify.php
310
ykval-verify.php
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user