<?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, "token" => $token); $add_token = ""; if (!empty($token)) $add_token = " AND 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 === FALSE) { 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) { 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(sha1($rg['ua']), 0, 8); if (strncmp($rg['sid'], "X", 1) == 0) { // We have a pre-login session. if (strlen($rg['token']) != 32) { rg_token_set_error("invalid token"); 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("sha1", $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"); break; } $ret = TRUE; break; } $rand = substr($rg['token'], 0, 16); $search = $rand . $ua_hash; $params = array("sid" => $rg['sid'], "token" => $search); $sql = "UPDATE tokens SET used = 1" . " WHERE token = @@token@@" . " AND sid = @@sid@@" . " AND used = 0"; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_token_set_error("cannot get token (" . rg_sql_error() . ")"); break; } $rows = rg_sql_affected_rows($res); rg_sql_free_result($res); if ($rows == 0) break; $ret = TRUE; break; } if ($ret === FALSE) rg_security_violation_no_exit("invalid token"); rg_log_exit(); rg_prof_end("token_valid"); return $ret; } /* * Insert a token */ function rg_token_insert($db, $sid, $token) { rg_prof_start("token_insert"); rg_log_enter("token_insert: sid=$sid token=$token"); $ret = array(); $ret['ok'] = 0; while (1) { $now = time(); $params = array("sid" => $sid, "token" => $token, "expire" => $now + 24 * 3600); $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; } $ret['ok'] = 1; break; } rg_log_exit(); rg_prof_end("token_insert"); 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; } $rand = rg_id(16); $ua_hash = substr(sha1($rg['ua']), 0, 8); if (strncmp($rg['sid'], "X", 1) == 0) { // we have a pre-login session $key = rg_token_get_master($db); if ($key === FALSE) break; $data = $rand . $rg['sid'] . $ua_hash; $sign = hash_hmac("sha1", $data, $key); if ($sign === FALSE) { rg_token_set_error("cannot compute hmac"); break; } $sign = substr($sign, 0, 16); $token = $rand . $sign; rg_log("DEBUG: sign=$sign rand=$rand sid=" . $rg['sid'] . " ua_hash=$ua_hash"); } else { $token = $rand . $ua_hash; $r = rg_token_insert($db, $rg['sid'], $token); if ($r['ok'] != 1) break; } $rg_token = $token; $ret = $token; break; } rg_log_exit(); return $ret; } ?>