diff --git a/lib/dmllib.php b/lib/dmllib.php index 30694b77435..1ce3ea6ebcf 100644 --- a/lib/dmllib.php +++ b/lib/dmllib.php @@ -569,6 +569,7 @@ function get_record_select($table, $select='', $fields='*') { function get_recordset($table, $field='', $value='', $sort='', $fields='*', $limitfrom='', $limitnum='') { if ($field) { + $value = sql_magic_quotes_hack($value); $select = "$field = '$value'"; } else { $select = ''; @@ -1433,7 +1434,7 @@ function delete_records_select($table, $select='') { * @param string $table The database table to be checked against. * @param object $dataobject A data object with values for one or more fields in the record * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned. - * @param string $primarykey (obsolete) This is now forced to be 'id'. + * @param string $primarykey (obsolete) This is now forced to be 'id'. */ function insert_record($table, $dataobject, $returnid=true, $primarykey='id') { @@ -1463,6 +1464,11 @@ function insert_record($table, $dataobject, $returnid=true, $primarykey='id') { /// so let's unset it now before it causes any trouble later unset($dataobject->{$primarykey}); +/// Extra protection against SQL injections + foreach((array)$dataobject as $k=>$v) { + $dataobject->$k = sql_magic_quotes_hack($v); + } + /// Get an empty recordset. Cache for multiple inserts. if (empty($empty_rs_cache[$table])) { /// Execute a dummy query to get an empty recordset @@ -1639,6 +1645,11 @@ function update_record($table, $dataobject) { $dataobject = (object)$dataobject; } +/// Extra protection against SQL injections + foreach((array)$dataobject as $k=>$v) { + $dataobject->$k = sql_magic_quotes_hack($v); + } + // Remove this record from record cache since it will change if (!empty($CFG->rcache)) { // no === here! breaks upgrade rcache_unset($table, $dataobject->id); @@ -2223,6 +2234,38 @@ function sql_ceil($fieldname) { } } +/** + * This hack prevents some types of SQL injections, no code should rely on this, + * do not forget to use addslashes() and addslashes_recursive() properly! + * + * The performance cost is negligible considering the security benefits and DB requests cost. + * + * @param mixed $value sql parameter value (hopefully with magic quotes) + * @return mixed sanitised value - added magic quotes if accidentally missing + */ +function sql_magic_quotes_hack($value) { + if ($value === null or $value === '') { + // performance shortcut + return $value; + } + + // ignore stuff that can not be converted to string, catchable fatal error will be displayed elsewhere, + // this is intentional because we want to get the same errors as before this magic hack + if (is_object($value)) { + if (!method_exists($value, '__toString')) { + // ignore - we can not cast object to string, error will be triggered elsewhere + return $value; + } + } else if (!is_string($value)) { + // no sql injection possible in other non-string values + return $value; + } + + // note: this does not change content if the content is properly escaped, + // the result is different only for strings with missing magic quotes! + return addslashes(stripslashes($value)); +} + /** * Prepare a SQL WHERE clause to select records where the given fields match the given values. * @@ -2238,6 +2281,9 @@ function sql_ceil($fieldname) { * @param string $value3 the value field3 must have (requred if field3 is given, else optional). */ function where_clause($field1='', $value1='', $field2='', $value2='', $field3='', $value3='') { + $value1 = sql_magic_quotes_hack($value1); + $value2 = sql_magic_quotes_hack($value2); + $value3 = sql_magic_quotes_hack($value3); if ($field1) { $select = is_null($value1) ? "WHERE $field1 IS NULL" : "WHERE $field1 = '$value1'"; if ($field2) {