<?php require_once($INC . "/util.inc.php"); require_once($INC . "/log.inc.php"); require_once($INC . "/sql.inc.php"); require_once($INC . "/prof.inc.php"); $rg_token_error = ""; function rg_token_set_error($str) { global $rg_token_error; $rg_token_error = $str; rg_log($str); } function rg_token_error() { global $rg_token_error; return $rg_token_error; } /* * Delete a token */ function rg_token_delete($db, $sid, $token) { rg_prof_start("token_delete"); rg_log_enter("token_delete: sid=$sid token=$token"); $ret = array(); $ret['ok'] = 0; while (1) { $params = array("sid" => $sid); $add_token = ""; if (!empty($token)) { $add_token = " AND token = @@token@@"; $params['token'] = $token; } $sql = "DELETE FROM tokens" . " WHERE sid = @@sid@@" . $add_token; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_token_set_error("cannot delete token (" . rg_sql_error() . ")"); break; } rg_sql_free_result($res); $ret['ok'] = 1; break; } rg_log_exit(); rg_prof_end("token_delete"); return $ret; } /* * This function will get the master key from db */ function rg_token_get_master($db) { rg_prof_start("token_get_master"); rg_log_enter("token_get_master"); $ret = FALSE; while (1) { $key = rg_state_get($db, "token_key"); if ($key === FALSE) { rg_token_set_error("cannot get token_key:" . " " . rg_state_error()); break; } if (empty($key)) { $key = rg_id(32); $r = rg_state_set($db, "token_key", $key); if ($r !== TRUE) { rg_token_set_error("cannot set state:" . " " . rg_state_error()); break; } } $ret = $key; break; } rg_log_exit(); rg_prof_end("token_get_master"); return $ret; } /* * Returns TRUE if the token is valid */ function rg_token_valid($db, $rg, $double_allowed) { rg_prof_start("token_valid"); rg_log_enter("token_valid: sid=" . $rg['sid'] . " token=" . $rg['token'] . " ua=" . $rg['ua']); $ret = FALSE; while (1) { $ua_hash = substr(sha512($rg['ua']), 0, 8); $len = strlen($rg['token']); if ($len != 32) { rg_token_set_error("invalid token"); rg_security_violation_no_exit("invalid token ($len != 32)"); break; } $key = rg_token_get_master($db); if ($key === FALSE) break; $rand = substr($rg['token'], 0, 16); $sign = substr($rg['token'], 16, 16); $data = $rand . $rg['sid'] . $ua_hash; $hash = hash_hmac("sha512", $data, $key); if ($hash === FALSE) { rg_token_set_error("cannot compute hmac"); break; } $hash = substr($hash, 0, 16); if (strcmp($sign, $hash) != 0) { rg_log("DEBUG: sign=$sign != hash=$hash data=$data"); rg_token_set_error("token invalid"); rg_security_violation_no_exit("invalid token (sign)"); break; } if (strncmp($rg['sid'], "X", 1) == 0) { // We have a pre-login session: we do not have to mark // the token as used. $ret = TRUE; break; } if ($double_allowed) { $ret = TRUE; break; } $params = array("sid" => $rg['sid'], "token" => $rg['token'], "expire" => time() + 24 * 3600); // We check to see if token was already used $sql = "SELECT 1 FROM tokens" . " WHERE sid = @@sid@@" . " AND token = @@token@@"; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_token_set_error("cannot check if token is used" . " (" . rg_sql_error() . ")"); break; } $rows = rg_sql_num_rows($res); rg_sql_free_result($res); if ($rows == 1) { rg_token_set_error("token already used"); break; } $sql = "INSERT INTO tokens (sid, token, expire)" . " VALUES (@@sid@@, @@token@@, @@expire@@)"; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_token_set_error("cannot insert token" . " (" . rg_sql_error() . ")"); break; } rg_sql_free_result($res); $ret = TRUE; break; } rg_log_exit(); rg_prof_end("token_valid"); return $ret; } /* * Returns a token to be used on a form/url * We generate only one per form, but multiple per session. */ $rg_token = FALSE; function rg_token_get($db, $rg) { global $rg_token; rg_log_enter("token_get: sid=" . $rg['sid']); $ret = FALSE; while (1) { if (empty($rg['sid'])) break; if ($rg_token !== FALSE) { $ret = $rg_token; break; } $key = rg_token_get_master($db); if ($key === FALSE) break; $rand = rg_id(16); $ua_hash = substr(sha512($rg['ua']), 0, 8); $data = $rand . $rg['sid'] . $ua_hash; $sign = hash_hmac("sha512", $data, $key); if ($sign === FALSE) { rg_token_set_error("cannot compute hmac"); break; } $sign = substr($sign, 0, 16); $rg_token = $rand . $sign; $ret = $rg_token; break; } rg_log_exit(); return $ret; } ?>