Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

include/database/MysqliManager.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3
/*********************************************************************************
4
 * SugarCRM Community Edition is a customer relationship management program developed by
5
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6
7
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
8
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
9
 *
10
 * This program is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU Affero General Public License version 3 as published by the
12
 * Free Software Foundation with the addition of the following permission added
13
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
14
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
15
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License along with
23
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
24
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
 * 02110-1301 USA.
26
 *
27
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
28
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
29
 *
30
 * The interactive user interfaces in modified source and object code versions
31
 * of this program must display Appropriate Legal Notices, as required under
32
 * Section 5 of the GNU Affero General Public License version 3.
33
 *
34
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
35
 * these Appropriate Legal Notices must retain the display of the "Powered by
36
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
37
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
38
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
39
 ********************************************************************************/
40
41
/*********************************************************************************
42
43
* Description: This file handles the Data base functionality for the application.
44
* It acts as the DB abstraction layer for the application. It depends on helper classes
45
* which generate the necessary SQL. This sql is then passed to PEAR DB classes.
46
* The helper class is chosen in DBManagerFactory, which is driven by 'db_type' in 'dbconfig' under config.php.
47
*
48
* All the functions in this class will work with any bean which implements the meta interface.
49
* The passed bean is passed to helper class which uses these functions to generate correct sql.
50
*
51
* The meta interface has the following functions:
52
* getTableName()                Returns table name of the object.
53
* getFieldDefinitions()         Returns a collection of field definitions in order.
54
* getFieldDefintion(name)       Return field definition for the field.
55
* getFieldValue(name)           Returns the value of the field identified by name.
56
*                               If the field is not set, the function will return boolean FALSE.
57
* getPrimaryFieldDefinition()   Returns the field definition for primary key
58
*
59
* The field definition is an array with the following keys:
60
*
61
* name      This represents name of the field. This is a required field.
62
* type      This represents type of the field. This is a required field and valid values are:
63
*           �   int
64
*           �   long
65
*           �   varchar
66
*           �   text
67
*           �   date
68
*           �   datetime
69
*           �   double
70
*           �   float
71
*           �   uint
72
*           �   ulong
73
*           �   time
74
*           �   short
75
*           �   enum
76
* length    This is used only when the type is varchar and denotes the length of the string.
77
*           The max value is 255.
78
* enumvals  This is a list of valid values for an enum separated by "|".
79
*           It is used only if the type is �enum�;
80
* required  This field dictates whether it is a required value.
81
*           The default value is �FALSE�.
82
* isPrimary This field identifies the primary key of the table.
83
*           If none of the fields have this flag set to �TRUE�,
84
*           the first field definition is assume to be the primary key.
85
*           Default value for this field is �FALSE�.
86
* default   This field sets the default value for the field definition.
87
*
88
*
89
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
90
* All Rights Reserved.
91
* Contributor(s): ______________________________________..
92
********************************************************************************/
93
94
require_once('include/database/MysqlManager.php');
95
96
/**
97
 * MySQL manager implementation for mysqli extension
98
 */
99
class MysqliManager extends MysqlManager
100
{
101
	/**
102
	 * @see DBManager::$dbType
103
	 */
104
	public $dbType = 'mysql';
105
	public $variant = 'mysqli';
106
	public $priority = 10;
107
	public $label = 'LBL_MYSQLI';
108
109
	/**
110
	 * @see DBManager::$backendFunctions
111
	 */
112
	protected $backendFunctions = array(
113
		'free_result'        => 'mysqli_free_result',
114
		'close'              => 'mysqli_close',
115
		'row_count'          => 'mysqli_num_rows',
116
		'affected_row_count' => 'mysqli_affected_rows',
117
		);
118
119
	/**
120
	 * @see MysqlManager::query()
121
	 */
122 896
	public function query($sql, $dieOnError = false, $msg = '', $suppress = false, $keepResult = false)
123
	{
124 896
		if(is_array($sql)) {
125
			return $this->queryArray($sql, $dieOnError, $msg, $suppress);
126
        }
127
128 896
		static $queryMD5 = array();
129
130 896
		parent::countQuery($sql);
0 ignored issues
show
The call to MysqlManager::countQuery() has too many arguments starting with $sql.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
131 896
		$GLOBALS['log']->info('Query:' . $sql);
132 896
		$this->checkConnection();
133 896
		$this->query_time = microtime(true);
0 ignored issues
show
Documentation Bug introduced by
The property $query_time was declared of type integer, but microtime(true) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
134 896
		$this->lastsql = $sql;
135 896
		$result = $suppress?@mysqli_query($this->database,$sql):mysqli_query($this->database,$sql);
136 896
		$md5 = md5($sql);
137
138 896
		if (empty($queryMD5[$md5]))
139 276
			$queryMD5[$md5] = true;
140
141 896
		$this->query_time = microtime(true) - $this->query_time;
0 ignored issues
show
Documentation Bug introduced by
The property $query_time was declared of type integer, but microtime(true) - $this->query_time is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
142 896
		$GLOBALS['log']->info('Query Execution Time:'.$this->query_time);
143
144
		// This is some heavy duty debugging, leave commented out unless you need this:
145
		/*
146
		$bt = debug_backtrace();
147
		for ( $i = count($bt) ; $i-- ; $i > 0 ) {
148
			if ( strpos('MysqliManager.php',$bt[$i]['file']) === false ) {
149
				$line = $bt[$i];
150
			}
151
		}
152
153
		$GLOBALS['log']->fatal("${line['file']}:${line['line']} ${line['function']} \nQuery: $sql\n");
154
		*/
155
156
157 896
		if($keepResult)
158
			$this->lastResult = $result;
159 896
		$this->checkError($msg.' Query Failed: ' . $sql, $dieOnError);
160
161 896
		return $result;
162
	}
163
164
	/**
165
	 * Returns the number of rows affected by the last query
166
	 *
167
	 * @return int
168
	 */
169 4
	public function getAffectedRowCount($result)
170
	{
171 4
		return mysqli_affected_rows($this->getDatabase());
172
	}
173
174
	/**
175
	 * Returns the number of rows returned by the result
176
	 *
177
	 * This function can't be reliably implemented on most DB, do not use it.
178
	 * @abstract
179
	 * @deprecated
180
	 * @param  resource $result
181
	 * @return int
182
	 */
183
	public function getRowCount($result)
184
	{
185
	    return mysqli_num_rows($result);
186
	}
187
188
189
    /**
190
	 * Disconnects from the database
191
	 *
192
	 * Also handles any cleanup needed
193
	 */
194
	public function disconnect()
195
	{
196
		if(isset($GLOBALS['log']) && !is_null($GLOBALS['log'])) {
197
			$GLOBALS['log']->debug('Calling MySQLi::disconnect()');
198
		}
199
		if(!empty($this->database)){
200
			$this->freeResult();
201
			mysqli_close($this->database);
202
			$this->database = null;
203
		}
204
	}
205
206
	/**
207
	 * @see DBManager::freeDbResult()
208
	 */
209 1
	protected function freeDbResult($dbResult)
210
	{
211 1
		if(!empty($dbResult))
212 1
			mysqli_free_result($dbResult);
213 1
	}
214
215
	/**
216
	 * @see DBManager::getFieldsArray()
217
	 */
218
	public function getFieldsArray($result, $make_lower_case = false)
219
	{
220
		$field_array = array();
221
222
		if (!isset($result) || empty($result))
223
			return 0;
224
225
		$i = 0;
226
		while ($i < mysqli_num_fields($result)) {
227
			$meta = mysqli_fetch_field_direct($result, $i);
228
			if (!$meta)
229
				return 0;
230
231
			if($make_lower_case == true)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
232
				$meta->name = strtolower($meta->name);
233
234
			$field_array[] = $meta->name;
235
236
			$i++;
237
		}
238
239
		return $field_array;
240
	}
241
242
	/**
243
	 * @see DBManager::fetchRow()
244
	 */
245 427
	public function fetchRow($result)
246
	{
247 427
		if (empty($result))	return false;
248
249 427
		$row = mysqli_fetch_assoc($result);
250 427
		if($row == null) $row = false; //Make sure MySQLi driver results are consistent with other database drivers
251 427
		return $row;
252
	}
253
254
	/**
255
	 * @see DBManager::quote()
256
	 */
257 220
	public function quote($string)
258
	{
259 220
		return mysqli_real_escape_string($this->getDatabase(),$this->quoteInternal($string));
260
	}
261
262
	/**
263
	 * @see DBManager::connect()
264
	 */
265 94
	public function connect(array $configOptions = null, $dieOnError = false)
266
	{
267 94
		global $sugar_config;
268
269 94
		if (is_null($configOptions))
270 94
			$configOptions = $sugar_config['dbconfig'];
271
272 94
		if(!isset($this->database)) {
273
274
			//mysqli connector has a separate parameter for port.. We need to separate it out from the host name
275 94
			$dbhost=$configOptions['db_host_name'];
276 94
            $dbport=isset($configOptions['db_port']) ? ($configOptions['db_port'] == '' ? null : $configOptions['db_port']) : null;
277
			
278 94
			$pos=strpos($configOptions['db_host_name'],':');
279 94
			if ($pos !== false) {
280
				$dbhost=substr($configOptions['db_host_name'],0,$pos);
281
				$dbport=substr($configOptions['db_host_name'],$pos+1);
282
			}
283
284 94
			$this->database = @mysqli_connect($dbhost,$configOptions['db_user_name'],$configOptions['db_password'],isset($configOptions['db_name'])?$configOptions['db_name']:'',$dbport);
285 94
			if(empty($this->database)) {
286
				$GLOBALS['log']->fatal("Could not connect to DB server ".$dbhost." as ".$configOptions['db_user_name'].". port " .$dbport . ": " . mysqli_connect_error());
287
				if($dieOnError) {
288
					if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) {
289
						sugar_die($GLOBALS['app_strings']['ERR_NO_DB']);
290
					} else {
291
						sugar_die("Could not connect to the database. Please refer to suitecrm.log for details.");
292
					}
293
				} else {
294
					return false;
295
				}
296
			}
297
		}
298
299 94
		if(!empty($configOptions['db_name']) && !@mysqli_select_db($this->database,$configOptions['db_name'])) {
300
			$GLOBALS['log']->fatal( "Unable to select database {$configOptions['db_name']}: " . mysqli_connect_error());
301
			if($dieOnError) {
302
					if(isset($GLOBALS['app_strings']['ERR_NO_DB'])) {
303
						sugar_die($GLOBALS['app_strings']['ERR_NO_DB']);
304
					} else {
305
						sugar_die("Could not connect to the database. Please refer to suitecrm.log for details.");
306
					}
307
			} else {
308
				return false;
309
			}
310
	    }
311
312
		// cn: using direct calls to prevent this from spamming the Logs
313
	    
314 94
	    $collation = $this->getOption('collation');
315 94
	    if(!empty($collation)) {
316
	    	$names = "SET NAMES 'utf8' COLLATE '$collation'";
317
	    	mysqli_query($this->database,$names);
318
		}
319 94
	    mysqli_set_charset ($this->database , "utf8" );
320
321 94
		if($this->checkError('Could Not Connect', $dieOnError))
322
			$GLOBALS['log']->info("connected to db");
323
324 94
		$this->connectOptions = $configOptions;
325 94
		return true;
326
	}
327
328
	/**
329
	 * (non-PHPdoc)
330
	 * @see MysqlManager::lastDbError()
331
	 */
332 896
	public function lastDbError()
333
	{
334 896
		if($this->database) {
335 896
		    if(mysqli_errno($this->database)) {
336 896
			    return "MySQL error ".mysqli_errno($this->database).": ".mysqli_error($this->database);
337
		    }
338
		} else {
339
			$err =  mysqli_connect_error();
340
			if($err) {
341
			    return $err;
342
			}
343
		}
344
345 896
		return false;
346
	}
347
348
	public function getDbInfo()
349
	{
350
		$charsets = $this->getCharsetInfo();
351
		$charset_str = array();
352
		foreach($charsets as $name => $value) {
353
			$charset_str[] = "$name = $value";
354
		}
355
		return array(
356
			"MySQLi Version" => @mysqli_get_client_info(),
357
			"MySQLi Host Info" => @mysqli_get_host_info($this->database),
358
			"MySQLi Server Info" => @mysqli_get_server_info($this->database),
359
			"MySQLi Client Encoding" =>  @mysqli_character_set_name($this->database),
360
			"MySQL Character Set Settings" => join(", ", $charset_str),
361
		);
362
	}
363
364
	/**
365
	 * Select database
366
	 * @param string $dbname
367
	 */
368
	protected function selectDb($dbname)
369
	{
370
		return mysqli_select_db($this->getDatabase(), $dbname);
371
	}
372
373
	/**
374
	 * Check if this driver can be used
375
	 * @return bool
376
	 */
377
	public function valid()
378
	{
379
		return function_exists("mysqli_connect") && empty($GLOBALS['sugar_config']['mysqli_disabled']);
380
	}
381
}
382