diff --git a/connect.inc.php b/connect.inc.php index 66126524..47e24cec 100644 --- a/connect.inc.php +++ b/connect.inc.php @@ -1,5 +1,5 @@ select_db($_GET["db"]) : isset($_GET["sql"]) || isset($_GET["dump"]) || isset($_GET["database"]) || isset($_GET["processlist"]) || isset($_GET["privileges"]))) { +if (!(strlen($_GET["db"]) ? $mysql->select_db($_GET["db"]) : isset($_GET["sql"]) || isset($_GET["dump"]) || isset($_GET["database"]) || isset($_GET["processlist"]) || isset($_GET["privileges"]) || isset($_GET["user"]))) { if (strlen($_GET["db"])) { unset($_SESSION["databases"][$_GET["server"]]); } diff --git a/index.php b/index.php index 9dd63f12..0b4b3a19 100644 --- a/index.php +++ b/index.php @@ -48,6 +48,8 @@ if (isset($_GET["dump"])) { include "./view.inc.php"; } elseif (isset($_GET["schema"])) { include "./schema.inc.php"; + } elseif (isset($_GET["privileges"])) { + include "./privileges.inc.php"; } else { // uses CSRF token include "./editing.inc.php"; if ($_POST) { @@ -83,8 +85,8 @@ if (isset($_GET["dump"])) { include "./procedure.inc.php"; } elseif (isset($_GET["trigger"])) { include "./trigger.inc.php"; - } elseif (isset($_GET["privileges"])) { - include "./privileges.inc.php"; + } elseif (isset($_GET["user"])) { + include "./user.inc.php"; } elseif (isset($_GET["processlist"])) { include "./processlist.inc.php"; } else { @@ -100,8 +102,8 @@ if (isset($_GET["dump"])) { echo "\n"; while ($row = $result->fetch_assoc()) { echo ""; - echo ""; - echo ''; + echo ""; + echo ''; echo '\n"; echo "\n"; } diff --git a/privileges.inc.php b/privileges.inc.php index 22918a6a..c231b5c2 100644 --- a/privileges.inc.php +++ b/privileges.inc.php @@ -1,90 +1,14 @@ lang('Privileges'))); - $privileges = array(); - $result = $mysql->query("SHOW PRIVILEGES"); - while ($row = $result->fetch_assoc()) { - foreach (explode(",", $row["Context"]) as $context) { - $privileges[$context][$row["Privilege"]] = $row["Comment"]; //! translation - } - } - $result->free(); - $privileges["Server Admin"] += $privileges["File access on server"]; - $privileges["Databases"]["Create routine"] = $privileges["Procedures"]["Create routine"]; - $privileges["Columns"] = array(); - foreach (array("Select", "Insert", "Update", "References") as $val) { - $privileges["Columns"][$val] = $privileges["Tables"][$val]; - } - unset($privileges["Server Admin"]["Usage"]); - unset($privileges["Procedures"]["Create routine"]); - unset($privileges["Functions"]["Create routine"]); - $grants = array(); - if (strlen($_GET["privileges"]) && ($result = $mysql->query("SHOW GRANTS FOR '" . $mysql->escape_string($_GET["name"]) . "'@'" . $mysql->escape_string($_GET["privileges"]) . "'"))) { //! Use information_schema for MySQL 5 - column names in column privileges are not escaped - while ($row = $result->fetch_row()) { - if (preg_match('~GRANT (.*) ON (.*) TO ~', $row[0], $match)) { //! escape part between ON and TO - preg_match_all('~ *([^(,]*[^ ,(])( *\\([^)]+\\))?~', $match[1], $matches, PREG_SET_ORDER); - foreach ($matches as $val) { - $grants["$match[2]$val[2]"][$val[1]] = true; - } - } - if (preg_match('~ WITH GRANT OPTION~', $row[0])) { //! don't check inside strings and identifiers - $grants[$match[2]]["GRANT OPTION"] = true; - } - } - $result->free(); - } - $grants[""] = true; - - foreach (array( - "Server Admin" => lang('Server'), - "Databases" => lang('Database'), - "Tables" => lang('Table'), - "Columns" => lang('Column'), - "Procedures" => lang('Procedure'), - "Functions" => lang('Function'), - ) as $key => $val) { - if ($privileges[$key]) { - echo "
" . htmlspecialchars($row["ROUTINE_TYPE"]) . "' . htmlspecialchars($row["ROUTINE_NAME"]) . '" . htmlspecialchars($row["ROUTINE_TYPE"]) . "' . htmlspecialchars($row["ROUTINE_NAME"]) . '' . lang('Alter') . "
\n"; - echo ""; - if ($key != "Server Admin") { - echo ""; - } - foreach ($privileges[$key] as $privilege => $comment) { - echo ''; - } - echo "\n"; - foreach ($grants as $object => $grant) { - if ($key == "Server Admin" ? $object == (isset($grants["*.*"]) ? "*.*" : "") - : !$object || (substr($object, -1) == ")" || $key == "Columns" ? substr($object, -1) == ")" xor $key != "Columns" - : (preg_match('~PROCEDURE ~', $object) ? $key == "Procedures" - : (preg_match('~FUNCTION ~', $object) ? $key == "Functions" - : (substr($object, -1) == "*" || $key == "Tables" - ))))) { - echo ""; - if ($key != "Server Admin") { - echo '"; - } - foreach ($privileges[$key] as $privilege => $comment) { - echo ""; - } - echo "\n"; - } - } - echo "
$val' . htmlspecialchars($privilege) . '
\n"; - } - } - //! DROP USER, name, server, password -} else { - page_header(lang('Privileges')); - echo '

' . lang('Create user') . "

\n"; - //! use mysql database if possible (GRANTEE not properly escaped) or CURRENT_USER in MySQL 4 in case of insufficient privileges - $result = $mysql->query("SELECT DISTINCT GRANTEE FROM information_schema.USER_PRIVILEGES"); - echo "\n"; - echo "\n"; - while ($row = $result->fetch_row()) { - preg_match("~'((?:[^']+|'')*)'@'((?:[^']+|'')+)'~", $row[0], $match); - echo '\n"; - } - echo "
 " . lang('Username') . "" . lang('Server') . "
' . lang('edit') . '' . htmlspecialchars(str_replace("''", "'", $match[1])) . "" . htmlspecialchars(str_replace("''", "'", $match[2])) . "
\n"; - $result->free(); +page_header(lang('Privileges')); +echo '

' . lang('Create user') . "

\n"; +$result = $mysql->query("SELECT User, Host FROM mysql.user ORDER BY Host, User"); +if (!$result) { + $result = $mysql->query("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', 1) AS User, SUBSTRING_INDEX(CURRENT_USER, '@', -1) AS Host"); } +echo "\n"; +echo "\n"; +while ($row = $result->fetch_assoc()) { + echo '\n"; +} +echo "
 " . lang('Username') . "" . lang('Server') . "
' . lang('edit') . '' . htmlspecialchars($row["User"]) . "" . htmlspecialchars($row["Host"]) . "
\n"; +$result->free(); diff --git a/user.inc.php b/user.inc.php new file mode 100644 index 00000000..9f942036 --- /dev/null +++ b/user.inc.php @@ -0,0 +1,168 @@ + $val) { + $new_grants[$val] = ((array) $new_grants[$val]) + ((array) $_POST["grants"][$key]); + } +} +$grants = array(); +$old_pass = ""; +if (isset($_GET["host"]) && ($result = $mysql->query("SHOW GRANTS FOR '" . $mysql->escape_string($_GET["user"]) . "'@'" . $mysql->escape_string($_GET["host"]) . "'"))) { //! Use information_schema for MySQL 5 - column names in column privileges are not escaped + while ($row = $result->fetch_row()) { + if (preg_match('~GRANT (.*) ON (.*) TO ~', $row[0], $match)) { //! escape the part between ON and TO + preg_match_all('~ *([^(,]*[^ ,(])( *\\([^)]+\\))?~', $match[1], $matches, PREG_SET_ORDER); + foreach ($matches as $val) { + $grants["$match[2]$val[2]"][$val[1]] = true; + } + } + if (preg_match('~ WITH GRANT OPTION~', $row[0])) { //! don't check inside strings and identifiers + $grants[$match[2]]["GRANT OPTION"] = true; + } + if (preg_match("~ IDENTIFIED BY PASSWORD '([^']+)~", $row[0], $match)) { + $old_pass = $match[1]; + } + } + $result->free(); +} + +if ($_POST && !$error) { + $old_user = $mysql->escape_string($_GET["user"]) . "'@'" . $mysql->escape_string($_GET["host"]); + $new_user = $mysql->escape_string($_POST["user"]) . "'@'" . (strlen($_POST["host"]) ? $mysql->escape_string($_POST["host"]) : "%"); + $identified = " IDENTIFIED BY" . ($_POST["hashed"] ? " PASSWORD" : "") . " '" . $mysql->escape_string($_POST["pass"]) . "'"; + if ($_POST["drop"]) { + if ($mysql->query("DROP USER '$old_user'")) { + redirect($SELF . "privileges=", lang('User has been dropped.')); + } + } elseif ($old_user == $new_user || $mysql->server_info < 5 || $mysql->query("CREATE USER '$new_user'$identified")) { + if ($old_user == $new_user || $mysql->server_info < 5) { + $mysql->query("GRANT USAGE ON *.* TO '$new_user'$identified"); + } + $revoke = array(); + foreach ($new_grants as $object => $grant) { + $grant = array_keys($grant); + if ($old_user == $new_user) { + $old_grant = array_keys((array) $grants[$object]); + $revoke = array_diff($old_grant, $grant); + $grant = array_diff($grant, $old_grant); + unset($grants[$object]); + } + if (preg_match('~^(.+)(\\(.*\\))?$~U', $object, $match) && ( + ($grant && !$mysql->query("GRANT " . implode("$match[2], ", $grant) . "$match[2] ON $match[1] TO '$new_user'")) //! SQL injection + || ($revoke && !$mysql->query("REVOKE " . implode("$match[2], ", $revoke) . "$match[2] ON $match[1] FROM '$new_user'")) + )) { + $error = $mysql->error; + if ($old_user != $new_user) { + $mysql->query("DROP USER '$new_user'"); + } + break; + } + } + if (!$error) { + if ($old_user != $new_user) { + $mysql->query("DROP USER '$old_user'"); + } else { + foreach ($grants as $object => $revoke) { + if (preg_match('~^(.+)(\\(.*\\))?$~U', $object, $match)) { + $mysql->query("REVOKE " . implode("$match[2], ", $revoke) . "$match[2] ON $match[1] FROM '$new_user'"); + } + } + } + redirect($SELF . "privileges=", (isset($_GET["host"]) ? lang('User has been altered.') : lang('User has been created.'))); + } + } + if (!$error) { + $error = $mysql->error; + } +} + +page_header((isset($_GET["host"]) ? lang('Username') . ": " . htmlspecialchars("$_GET[user]@$_GET[host]") : lang('Create user')), array("privileges" => lang('Privileges'))); +$privileges = array(); +$result = $mysql->query("SHOW PRIVILEGES"); +while ($row = $result->fetch_assoc()) { + foreach (explode(",", $row["Context"]) as $context) { + $privileges[$context][$row["Privilege"]] = $row["Comment"]; //! translation + } +} +$result->free(); +$privileges["Server Admin"] += $privileges["File access on server"]; +$privileges["Databases"]["Create routine"] = $privileges["Procedures"]["Create routine"]; +$privileges["Columns"] = array(); +foreach (array("Select", "Insert", "Update", "References") as $val) { + $privileges["Columns"][$val] = $privileges["Tables"][$val]; +} +unset($privileges["Server Admin"]["Usage"]); +unset($privileges["Procedures"]["Create routine"]); +foreach ($privileges["Tables"] as $key => $val) { + unset($privileges["Databases"][$key]); +} +//! JS checkbox for all + +if ($_POST) { + $row = $_POST; + $grants = $new_grants; + echo "

" . lang('Unable to operate user') . ": " . htmlspecialchars($error) . "

\n"; +} else { + $row = $_GET; + $row["pass"] = $old_pass; + if (strlen($old_pass)) { + $row["hashed"] = true; + } + $grants[""] = true; +} + +?> +
+ + + + +
" />
" />
" />
+ +

+ lang('Server'), + "Databases" => lang('Database'), + "Tables" => lang('Table'), + "Columns" => lang('Column'), + "Procedures" => lang('Routine'), +) as $key => $val) { + if ($privileges[$key]) { + echo "\n"; + echo ""; + if ($key != "Server Admin") { + echo ""; + } + foreach ($privileges[$key] as $privilege => $comment) { + echo ''; + } + echo "\n"; + foreach ($grants as $object => $grant) { + if ($key == "Server Admin" ? $object == (isset($grants["*.*"]) ? "*.*" : "") + : !$object || (substr($object, -1) == ")" || $key == "Columns" ? substr($object, -1) == ")" xor $key != "Columns" + : (preg_match('~(PROCEDURE|FUNCTION) ~', $object) ? $key == "Procedures" + : (substr($object, -1) == "*" || $key == "Tables" + )))) { + echo ""; + if ($key != "Server Admin") { + echo '"; //! separate db, table, columns, PROCEDURE|FUNCTION, routine + } + foreach ($privileges[$key] as $privilege => $comment) { + echo '"; + } + echo "\n"; + $i++; + } + } + echo "
$val' . htmlspecialchars($privilege) . '
\n"; + } +} +?> +

+ + + +

+