From 13f1a28b6ef9c6bc82ab257cef7af4686f53933c Mon Sep 17 00:00:00 2001 From: Christian Boltz Date: Sun, 2 Nov 2014 22:45:22 +0000 Subject: [PATCH] PFAHandler: - read_from_db(), getList(): - add $searchmode parameter (_before_ $limit and $offset!) to be able to use query different query modes, not only "=" - add a warning that $condition will be changed to array only in the future - getList(): filter $condition for fields that are available to the user to avoid information leaks by using search parameters (filter is only applied if $condition is an array!) functions.inc.php: - db_where_clause(): - add $additional_raw_where parameter for additional query parameters - add $searchmode parameter to be able to use query different query modes, not only "=" (see $allowed_operators) - check for allowed operators in $searchmode - split query into WHERE and HAVING (if a parameter has $struct[select] set, HAVING is used) list-virtual.php: - adopt getList() call to the new syntax AliasHandler: - adopt getList() definition and call to the new syntax git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/trunk@1731 a1433add-5e2c-0410-b055-b7f2511e0802 --- functions.inc.php | 39 +++++++++++++++++++++++++++++++++--- list-virtual.php | 2 +- model/AliasHandler.php | 4 ++-- model/PFAHandler.php | 45 +++++++++++++++++++++++++++++++----------- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/functions.inc.php b/functions.inc.php index 2bfe10e1..4ba9ba0b 100644 --- a/functions.inc.php +++ b/functions.inc.php @@ -1617,21 +1617,54 @@ function db_in_clause($field, $values) { * Call: db_where_clause (array $conditions, array $struct) * param array $conditios: array('field' => 'value', 'field2' => 'value2, ...) * param array $struct - field structure, used for automatic bool conversion + * param string $additional_raw_where - raw sniplet to include in the WHERE part - typically needs to start with AND + * param array $searchmode - operators to use (=, <, > etc.) - defaults to = if not specified for a field (see + * $allowed_operators for available operators) */ -function db_where_clause($condition, $struct) { +function db_where_clause($condition, $struct, $additional_raw_where = '', $searchmode = array()) { if (!is_array($condition)) { die('db_where_cond: parameter $cond is not an array!'); + } elseif(!is_array($searchmode)) { + die('db_where_cond: parameter $searchmode is not an array!'); } elseif (count($condition) == 0) { die("db_where_cond: parameter is an empty array!"); # die() might sound harsh, but can prevent information leaks } elseif(!is_array($struct)) { die('db_where_cond: parameter $struct is not an array!'); } + $allowed_operators = explode(' ', '< > >= <= = != <> CONT LIKE'); + $where_parts = array(); + $having_parts = array(); + foreach($condition as $field => $value) { if (isset($struct[$field]) && $struct[$field]['type'] == 'bool') $value = db_get_boolean($value); - $parts[] = "$field='" . escape_string($value) . "'"; + $operator = '='; + if (isset($searchmode[$field])) { + if (in_array($searchmode[$field], $allowed_operators)) { + $operator = $searchmode[$field]; + + if ($operator == 'CONT') { # CONT - as in "contains" + $operator = ' LIKE '; # add spaces + $value = '%' . $value . '%'; + } elseif ($operator == 'LIKE') { # LIKE -without adding % wildcards (the search value can contain %) + $operator = ' LIKE '; # add spaces + } + } else { + die('db_where_clause: Invalid searchmode for ' . $field); + } + } + $querypart = $field . $operator . "'" . escape_string($value) . "'"; + if($struct[$field]['select'] != '') { + $having_parts[$field] = $querypart; + } else { + $where_parts[$field] = $querypart; + } } - $query = " WHERE ( " . join(" AND ", $parts) . " ) "; + $query = ' WHERE 1=1 '; + $query .= " $additional_raw_where "; + if (count($where_parts) > 0) $query .= " AND ( " . join(" AND ", $where_parts) . " ) "; + if (count($having_parts) > 0) $query .= " HAVING ( " . join(" AND ", $having_parts) . " ) "; + return $query; } diff --git a/list-virtual.php b/list-virtual.php index 21fc6892..f5487af6 100644 --- a/list-virtual.php +++ b/list-virtual.php @@ -126,7 +126,7 @@ $alias_pagebrowser_query = " "; $handler = new AliasHandler(0, $admin_username); -$handler->getList($list_param, $page_size, $fDisplay); +$handler->getList($list_param, array(), $page_size, $fDisplay); $tAlias = $handler->result(); diff --git a/model/AliasHandler.php b/model/AliasHandler.php index ab96b78a..ec71127f 100644 --- a/model/AliasHandler.php +++ b/model/AliasHandler.php @@ -287,10 +287,10 @@ class AliasHandler extends PFAHandler { return $db_result; } - public function getList($condition, $limit=-1, $offset=-1) { + public function getList($condition, $searchmode = array(), $limit=-1, $offset=-1) { # only list aliases that do not belong to mailboxes # TODO: breaks if $condition is an array - return parent::getList( "__mailbox_username IS NULL AND ( $condition )", $limit, $offset); + return parent::getList( "__mailbox_username IS NULL AND ( $condition )", $searchmode, $limit, $offset); } protected function _validate_goto($field, $val) { diff --git a/model/PFAHandler.php b/model/PFAHandler.php index 2eef1a21..9456a022 100644 --- a/model/PFAHandler.php +++ b/model/PFAHandler.php @@ -533,11 +533,13 @@ abstract class PFAHandler { * * @param array or string - condition (an array will be AND'ed using db_where_clause, a string will be directly used) * (if you use a string, make sure it is correctly escaped!) + * - WARNING: will be changed to array only in the future, with an option to include a raw string inside the array + * @param array searchmode - operators to use (=, <, >) if $condition is an array. Defaults to = if not specified for a field. * @param integer limit - maximum number of rows to return * @param integer offset - number of first row to return * @return array - rows (as associative array, with the ID as key) */ - protected function read_from_db($condition, $limit=-1, $offset=-1) { + protected function read_from_db($condition, $searchmode = array(), $limit=-1, $offset=-1) { $select_cols = array(); $yes = escape_string(Config::lang('YES')); @@ -577,21 +579,23 @@ abstract class PFAHandler { $cols = join(',', $select_cols); $table = table_by_key($this->db_table); - if (is_array($condition)) { - $where = db_where_clause($condition, $this->struct); - } else { - if ($condition == "") $condition = '1=1'; - $where = " WHERE ( $condition ) "; - } - + $additional_where = ''; if ($this->domain_field != "") { - $where .= " AND " . db_in_clause($this->domain_field, $this->allowed_domains); + $additional_where .= " AND " . db_in_clause($this->domain_field, $this->allowed_domains); } # if logged in as user, restrict to the items the user is allowed to see if ( (!$this->is_admin) && $this->user_field != '') { - $where .= " AND " . $this->user_field . " = '" . escape_string($this->username) . "' "; + $additional_where .= " AND " . $this->user_field . " = '" . escape_string($this->username) . "' "; } + + if (is_array($condition)) { + $where = db_where_clause($condition, $this->struct, $additional_where, $searchmode); + } else { + if ($condition == "") $condition = '1=1'; + $where = " WHERE ( $condition ) $additional_where"; + } + $query = "SELECT $cols FROM $table $extrafrom $where ORDER BY " . $this->order_by; $limit = (int) $limit; # make sure $limit and $offset are really integers @@ -644,13 +648,30 @@ abstract class PFAHandler { /** * get a list of one or more items with all values * @param array or string $condition - see read_from_db for details + * WARNING: will be changed to array only in the future, with an option to include a raw string inside the array + * @param array - modes to use if $condition is an array - see read_from_db for details * @param integer limit - maximum number of rows to return * @param integer offset - number of first row to return * @return bool - always true, no need to check ;-) (if $result is not an array, getList die()s) * The data is stored in $this->result (as array of rows, each row is an associative array of column => value) */ - public function getList($condition, $limit=-1, $offset=-1) { - $result = $this->read_from_db($condition, $limit, $offset); + public function getList($condition, $searchmode = array(), $limit=-1, $offset=-1) { + if (is_array($condition)) { + $real_condition = array(); + foreach ($condition as $key => $value) { + # allow only access to fields the user can access to avoid information leaks via search parameters + if (isset($this->struct[$key]) && ($this->struct[$key]['display_in_list'] || $this->struct[$key]['display_in_form']) ) { + $real_condition[$key] = $value; + } else { + $this->errormsg[] = "Ignoring unknown search field $key"; + } + } + } else { + # warning: no sanity checks are applied if $condition is not an array! + $real_condition = $condition; + } + + $result = $this->read_from_db($real_condition, $searchmode, $limit, $offset); if (!is_array($result)) { error_log('getList: read_from_db didn\'t return an array. table: ' . $this->db_table . ' - condition: $condition - limit: $limit - offset: $offset');