@@ -239,7 +239,7 @@ private function securityScan($string) {
239239 }
240240 }
241241 }
242- if ($ ok == true ) {
242+ if ($ ok ) {
243243 return true ;
244244 } else {
245245 if ($ ids_config ['sql_scan_action ' ] == 'warn ' ) {
@@ -252,6 +252,8 @@ private function securityScan($string) {
252252 }
253253 }
254254 }
255+
256+ return true ;
255257 }
256258
257259 private function _query ($ sQuery = '' ) {
@@ -298,7 +300,9 @@ private function _query($sQuery = '') {
298300 } while ($ ok == false );
299301
300302 $ sQuery = call_user_func_array (array (&$ this , '_build_query_string ' ), $ aArgs );
301- $ this ->securityScan ($ sQuery );
303+ if (!$ this ->securityScan ($ sQuery )) {
304+ return false ;
305+ }
302306 $ this ->_iQueryId = mysqli_query ($ this ->_iConnId , $ sQuery );
303307 if (!$ this ->_iQueryId ) {
304308 $ this ->_sqlerror ('Falsche Anfrage / Wrong Query ' , 'SQL-Query = ' . $ sQuery );
@@ -590,6 +594,7 @@ public function unquote($formfield) {
590594 }
591595
592596 public function toLower ($ record ) {
597+ $ out = [];
593598 if (is_array ($ record )) {
594599 foreach ($ record as $ key => $ val ) {
595600 $ key = strtolower ($ key );
@@ -678,7 +683,7 @@ public function getDatabaseSize($database_name) {
678683 $ result = $ db ->_query ("SELECT SUM(data_length+index_length) FROM information_schema.TABLES WHERE table_schema=' " .$ db ->escape ($ database_name )."' " );
679684 if (!$ result ) {
680685 $ db ->_sqlerror ('Unable to determine the size of database ' . $ database_name );
681- return ;
686+ return 0 ;
682687 }
683688 $ database_size = $ result ->getAsRow ();
684689 $ result ->free ();
@@ -1075,7 +1080,7 @@ function tableInfo($table_name) {
10751080 }
10761081
10771082 public function mapType ($ metaType , $ typeValue ) {
1078- global $ go_api ;
1083+ global $ app ;
10791084 $ metaType = strtolower ($ metaType );
10801085 switch ($ metaType ) {
10811086 case 'int16 ' :
@@ -1107,6 +1112,8 @@ public function mapType($metaType, $typeValue) {
11071112 return 'date ' ;
11081113 break ;
11091114 }
1115+ $ app ->error ('Unknown meta type: ' .$ metaType );
1116+ return false ;
11101117 }
11111118
11121119 /**
@@ -1148,36 +1155,173 @@ public function getDatabaseVersion($major_version_only = false) {
11481155 * Get a mysql password hash
11491156 *
11501157 * @access public
1151- * @param string cleartext password
1158+ * @param string $password cleartext password
1159+ * @param string $hash_type MySQL hash type to use. either mysql_native_password or caching_sha2_password
11521160 * @return string Password hash
11531161 */
11541162
1155- public function getPasswordHash ($ password ) {
1163+ public function getPasswordHash ($ password , $ hash_type = 'mysql_native_password ' ) {
1164+ if ($ hash_type == 'caching_sha2_password ' ) {
1165+ $ password_hash = $ this ->mysqlSha256Crypt ($ password , $ this ->genSalt (20 ), 5000 );
1166+ } else {
1167+ $ password_hash = '* ' . strtoupper (sha1 (sha1 ($ password , true )));
1168+ }
11561169
1157- $ password_type = 'password ' ;
1170+ return $ password_hash ;
1171+ }
11581172
1159- /* Disabled until caching_sha2_password is implemented
1160- if($this->getDatabaseType() == 'mysql' && $this->getDatabaseVersion(true) >= 8) {
1161- // we are in MySQL 8 mode
1162- $tmp = $this->queryOneRecord("show variables like 'default_authentication_plugin'");
1163- if($tmp['default_authentication_plugin'] == 'caching_sha2_password') {
1164- $password_type = 'caching_sha2_password';
1173+ /**
1174+ * @param $size int length of salt in bytes
1175+ *
1176+ * @return string
1177+ */
1178+ private function genSalt ($ size ) {
1179+ $ salt = random_bytes ($ size );
1180+ if ($ salt === false ) {
1181+ throw new Exception ('Cannot generate salt. ' );
1182+ }
1183+ for ($ i = 0 ; $ i < $ size ; $ i ++) {
1184+ $ ord = ord ($ salt [$ i ]) & 0x7f ;
1185+ if ($ ord < 32 ) {
1186+ $ ord += 32 ;
1187+ }
1188+ if ($ ord == 36 /* $ */ ) {
1189+ $ ord += 1 ;
11651190 }
1191+ $ salt [$ i ] = chr ($ ord );
11661192 }
1167- */
11681193
1169- if ($ password_type == 'caching_sha2_password ' ) {
1170- /*
1171- caching_sha2_password hashing needs to be implemented, have not
1172- found valid PHP implementation for the new password hash type.
1173- */
1174- } else {
1175- $ password_hash = '* ' .strtoupper (sha1 (sha1 ($ password , true )));
1194+ return $ salt ;
1195+ }
1196+
1197+ /**
1198+ * this is the SHA256 algorithm of the crypt unix call – the only difference is that we do not truncate the salt to 16 chars
1199+ * @see https://www.akkadia.org/drepper/SHA-crypt.txt
1200+ * @see https://github.com/mysql/mysql-server/blob/trunk/mysys/crypt_genhash_impl.cc
1201+ *
1202+ * @param string $plaintext the plain text password
1203+ * @param string $salt the raw salt (needs to be 20 bytes long)
1204+ * @param int $rounds number of rounds. MySQL default is 5000. Must be between 1000 and 4095000 (0xFFF * 1000)
1205+ *
1206+ * @return string hashed password in MySQL format
1207+ */
1208+ private function mysqlSha256Crypt ($ plaintext , $ salt , $ rounds ) {
1209+ $ plaintext_len = strlen ($ plaintext );
1210+ $ salt_len = strlen ($ salt );
1211+
1212+ // 1
1213+ $ ctxA = hash_init ('sha256 ' );
1214+ // 2
1215+ hash_update ($ ctxA , $ plaintext );
1216+ // 3
1217+ hash_update ($ ctxA , $ salt );
1218+ // 4
1219+ $ ctxB = hash_init ('sha256 ' );
1220+ // 5
1221+ hash_update ($ ctxB , $ plaintext );
1222+ // 6
1223+ hash_update ($ ctxB , $ salt );
1224+ // 7
1225+ hash_update ($ ctxB , $ plaintext );
1226+ // 8
1227+ $ B = hash_final ($ ctxB , true );
1228+ // 9
1229+ for ($ i = $ plaintext_len ; $ i > 32 ; $ i -= 32 ) {
1230+ hash_update ($ ctxA , $ B );
11761231 }
1232+ // 10
1233+ hash_update ($ ctxA , substr ($ B , 0 , $ i ));
1234+ // 11
1235+ for ($ i = $ plaintext_len ; $ i > 0 ; $ i >>= 1 ) {
1236+ if (($ i & 1 ) != 0 ) {
1237+ hash_update ($ ctxA , $ B );
1238+ } else {
1239+ hash_update ($ ctxA , $ plaintext );
1240+ }
1241+ }
1242+ // 12
1243+ $ A = hash_final ($ ctxA , true );
1244+ // 13
1245+ $ ctxDP = hash_init ('sha256 ' );
1246+ // 14
1247+ for ($ i = 0 ; $ i < $ plaintext_len ; $ i ++) {
1248+ hash_update ($ ctxDP , $ plaintext );
1249+ }
1250+ // 15
1251+ $ DP = hash_final ($ ctxDP , true );
1252+ // 16
1253+ $ P = "" ;
1254+ for ($ i = $ plaintext_len ; $ i > 32 ; $ i -= 32 ) {
1255+ $ P .= $ DP ;
1256+ }
1257+ $ P .= substr ($ DP , 0 , $ i );
1258+ // 17
1259+ $ ctxDS = hash_init ('sha256 ' );
1260+ // 18
1261+ for ($ i = 0 ; $ i < 16 + ord ($ A [0 ]); $ i ++) {
1262+ hash_update ($ ctxDS , $ salt );
1263+ }
1264+ // 19
1265+ $ DS = hash_final ($ ctxDS , true );
1266+ // 20
1267+ $ S = "" ;
1268+ for ($ i = $ salt_len ; $ i >= 32 ; $ i -= 32 ) {
1269+ $ S .= $ DS ;
1270+ }
1271+ $ S .= substr ($ DS , 0 , $ i );
1272+ // 21
1273+ $ C = "" ;
1274+ for ($ i = 0 ; $ i < $ rounds ; $ i ++) {
1275+ $ ctxC = hash_init ('sha256 ' );
1276+ if (($ i & 1 ) != 0 ) {
1277+ hash_update ($ ctxC , $ P );
1278+ } else {
1279+ hash_update ($ ctxC , $ i == 0 ? $ A : $ C );
1280+ }
11771281
1178- return $ password_hash ;
1179- }
1282+ if ($ i % 3 != 0 ) {
1283+ hash_update ($ ctxC , $ S );
1284+ }
1285+
1286+ if ($ i % 7 != 0 ) {
1287+ hash_update ($ ctxC , $ P );
1288+ }
1289+
1290+ if (($ i & 1 ) != 0 ) {
1291+ hash_update ($ ctxC , $ i == 0 ? $ A : $ C );
1292+ } else {
1293+ hash_update ($ ctxC , $ P );
1294+ }
1295+ $ C = hash_final ($ ctxC , true );
1296+ }
11801297
1298+ // 22
1299+ $ b64result = str_repeat (' ' , 43 );
1300+ $ p = 0 ;
1301+ $ b64_from_24bit = function ($ B2 , $ B1 , $ B0 , $ N ) use (&$ b64result , &$ p ) {
1302+ $ b64_alphabet = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz " ;
1303+ $ w = ($ B2 << 16 ) | ($ B1 << 8 ) | $ B0 ;
1304+ $ n = $ N ;
1305+ while (--$ n >= 0 ) {
1306+ $ b64result [$ p ++] = $ b64_alphabet [$ w & 0x3f ];
1307+ $ w = $ w >> 6 ;
1308+ }
1309+ };
1310+ $ b64_from_24bit (ord ($ C [0 ]), ord ($ C [10 ]), ord ($ C [20 ]), 4 );
1311+ $ b64_from_24bit (ord ($ C [21 ]), ord ($ C [1 ]), ord ($ C [11 ]), 4 );
1312+ $ b64_from_24bit (ord ($ C [12 ]), ord ($ C [22 ]), ord ($ C [2 ]), 4 );
1313+ $ b64_from_24bit (ord ($ C [3 ]), ord ($ C [13 ]), ord ($ C [23 ]), 4 );
1314+ $ b64_from_24bit (ord ($ C [24 ]), ord ($ C [4 ]), ord ($ C [14 ]), 4 );
1315+ $ b64_from_24bit (ord ($ C [15 ]), ord ($ C [25 ]), ord ($ C [5 ]), 4 );
1316+ $ b64_from_24bit (ord ($ C [6 ]), ord ($ C [16 ]), ord ($ C [26 ]), 4 );
1317+ $ b64_from_24bit (ord ($ C [27 ]), ord ($ C [7 ]), ord ($ C [17 ]), 4 );
1318+ $ b64_from_24bit (ord ($ C [18 ]), ord ($ C [28 ]), ord ($ C [8 ]), 4 );
1319+ $ b64_from_24bit (ord ($ C [9 ]), ord ($ C [19 ]), ord ($ C [29 ]), 4 );
1320+ $ b64_from_24bit (0 , ord ($ C [31 ]), ord ($ C [30 ]), 3 );
1321+
1322+ // we do not truncate $salt to 16 chars since MySQL does not do that and uses 20 bytes salts
1323+ return sprintf ('$A$%03x$%s%s ' , $ rounds / 1000 , $ salt , $ b64result );
1324+ }
11811325
11821326}
11831327
@@ -1191,10 +1335,11 @@ class db_result {
11911335
11921336 /**
11931337 *
1194- *
1338+ * @var mysqli_result|null
11951339 * @access private
11961340 */
11971341 private $ _iResId = null ;
1342+ /** @var mysqli|null */
11981343 private $ _iConnection = null ;
11991344
12001345
@@ -1406,7 +1551,7 @@ public function getAsRow() {
14061551 *
14071552 * @access public
14081553 * @param int $iStart offset to start read
1409- * @param int iLength amount of datasets to read
1554+ * @param int $ iLength amount of datasets to read
14101555 */
14111556 public function limit_result ($ iStart , $ iLength ) {
14121557 $ this ->aLimitedData = array_slice ($ this ->aResultData , $ iStart , $ iLength , true );
0 commit comments