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/utils/file_utils.php (2 issues)

Labels
Severity

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
require_once('include/utils/array_utils.php');
43
require_once('include/utils/sugar_file_utils.php');
44
45
/**
46
 * Convert all \ to / in path, remove multiple '/'s and '/./'
47
 * @param string $path
48
 * @return string
49
 */
50
function clean_path( $path )
51
{
52
    // clean directory/file path with a functional equivalent
53 4
    $appendpath = '';
54 4
    if ( is_windows() && strlen($path) >= 2 && $path[0].$path[1] == "\\\\" ) {
55
        $path = substr($path,2);
56
        $appendpath = "\\\\";
57
    }
58 4
    $path = str_replace( "\\", "/", $path );
59 4
    $path = str_replace( "//", "/", $path );
60 4
    $path = str_replace( "/./", "/", $path );
61 4
    return( $appendpath.$path );
62
}
63
64
function create_cache_directory($file)
65
{
66 870
    $paths = explode('/',$file);
67 870
    $dir = rtrim($GLOBALS['sugar_config']['cache_dir'], '/\\');
68 870
    if(!file_exists($dir))
69
    {
70
        sugar_mkdir($dir, 0775);
71
    }
72 870
    for($i = 0; $i < sizeof($paths) - 1; $i++)
73
    {
74 870
        $dir .= '/' . $paths[$i];
75 870
        if(!file_exists($dir))
76
        {
77 11
            sugar_mkdir($dir, 0775);
78
        }
79
    }
80 870
    return $dir . '/'. $paths[sizeof($paths) - 1];
81
}
82
83
function get_module_dir_list()
84
{
85 1
	$modules = array();
86 1
	$path = 'modules';
87 1
	$d = dir($path);
88 1
	while($entry = $d->read())
89
	{
90 1
		if($entry != '..' && $entry != '.')
91
		{
92 1
			if(is_dir($path. '/'. $entry))
93
			{
94 1
				$modules[$entry] = $entry;
95
			}
96
		}
97
	}
98 1
	return $modules;
99
}
100
101
function mk_temp_dir( $base_dir, $prefix="" )
102
{
103 1
    $temp_dir = tempnam( $base_dir, $prefix );
104 1
    if( !$temp_dir || !unlink( $temp_dir ) )
105
    {
106
        return( false );
107
    }
108
109 1
    if( sugar_mkdir( $temp_dir ) ){
110 1
        return( $temp_dir );
111
    }
112
113
    return( false );
114
}
115
116
function remove_file_extension( $filename )
117
{
118 1
    return( substr( $filename, 0, strrpos($filename, ".") ) );
119
}
120
121
function write_array_to_file( $the_name, $the_array, $the_file, $mode="w", $header='' )
122
{
123 31
    if(!empty($header) && ($mode != 'a' || !file_exists($the_file))){
124
		$the_string = $header;
125
	}else{
126
    	$the_string =   "<?php\n" .
127 31
                    '// created: ' . date('Y-m-d H:i:s') . "\n";
128
	}
129 31
    $the_string .=  "\$$the_name = " .
130 31
                    var_export_helper( $the_array ) .
131 31
                    ";";
132
133 31
    $result = sugar_file_put_contents($the_file, $the_string, LOCK_EX) !== false;
134
135 31
    if (function_exists('opcache_invalidate')) {
136 31
        opcache_invalidate($the_file, true);
137
    }
138
139 31
    return $result;
140
}
141
142
function write_encoded_file( $soap_result, $write_to_dir, $write_to_file="" )
143
{
144
    // this function dies when encountering an error -- use with caution!
145
    // the path/file is returned upon success
146
147
148
149 1
    if( $write_to_file == "" )
150
    {
151 1
        $write_to_file = $write_to_dir . "/" . $soap_result['filename'];
152
    }
153
154 1
    $file = $soap_result['data'];
155 1
    $write_to_file = str_replace( "\\", "/", $write_to_file );
156
157 1
    $dir_to_make = dirname( $write_to_file );
158 1
    if( !is_dir( $dir_to_make ) )
159
    {
160
        mkdir_recursive( $dir_to_make );
161
    }
162 1
    $fh = sugar_fopen( $write_to_file, "wb" );
163 1
    fwrite( $fh, base64_decode( $file ) );
164 1
    fclose( $fh );
165
166 1
    if( md5_file( $write_to_file ) != $soap_result['md5'] )
167
    {
168
        die( "MD5 error after writing file $write_to_file" );
169
    }
170 1
    return( $write_to_file );
171
}
172
173
function create_custom_directory($file)
174
{
175 2
    $paths = explode('/',$file);
176 2
    $dir = 'custom';
177 2
    if(!file_exists($dir))
178
    {
179
        sugar_mkdir($dir, 0755);
180
    }
181 2
    for($i = 0; $i < sizeof($paths) - 1; $i++)
182
    {
183 2
        $dir .= '/' . $paths[$i];
184 2
        if(!file_exists($dir))
185
        {
186 2
            sugar_mkdir($dir, 0755);
187
        }
188
    }
189 2
    return $dir . '/'. $paths[sizeof($paths) - 1];
190
}
191
192
/**
193
 * This function will recursively generates md5s of files and returns an array of all md5s.
194
 *
195
 * @param	$path The path of the root directory to scan - must end with '/'
196
 * @param	$ignore_dirs array of filenames/directory names to ignore running md5 on - default 'cache' and 'upload'
197
 * @result	$md5_array an array containing path as key and md5 as value
198
 */
199
function generateMD5array($path, $ignore_dirs = array('cache', 'upload'))
200
{
201 2
	$dh  = opendir($path);
202 2
    if(!$dh){
203
        return array();
204
    }
205 2
	while (false !== ($filename = readdir($dh)))
206
	{
207 2
		$current_dir_content[] = $filename;
208
	}
209
210
	// removes the ignored directories
211 2
	$current_dir_content = array_diff($current_dir_content, $ignore_dirs);
212
213 2
	sort($current_dir_content);
214 2
	$md5_array = array();
215
216 2
	foreach($current_dir_content as $file)
217
	{
218
		// make sure that it's not dir '.' or '..'
219 2
		if(strcmp($file, ".") && strcmp($file, ".."))
220
		{
221 2
			if(is_dir($path.$file))
222
			{
223
				// For testing purposes - uncomment to see all files and md5s
224
				//echo "<BR>Dir:  ".$path.$file."<br>";
225
				//generateMD5array($path.$file."/");
226
227 1
				$md5_array += generateMD5array($path.$file."/", $ignore_dirs);
228
			}
229
			else
230
			{
231
				// For testing purposes - uncomment to see all files and md5s
232
				//echo "   File: ".$path.$file."<br>";
233
				//echo md5_file($path.$file)."<BR>";
234
235 2
				$md5_array[$path.$file] = md5_file($path.$file);
236
			}
237
		}
238
	}
239
240 2
	return $md5_array;
241
242
}
243
244
/**
245
 * Function to compare two directory structures and return the items in path_a that didn't match in path_b
246
 *
247
 * @param	$path_a The path of the first root directory to scan - must end with '/'
248
 * @param	$path_b The path of the second root directory to scan - must end with '/'
249
 * @param	$ignore_dirs array of filenames/directory names to ignore running md5 on - default 'cache' and 'upload'
250
 * @result	array containing all the md5s of everything in $path_a that didn't have a match in $path_b
251
 */
252
function md5DirCompare($path_a, $path_b, $ignore_dirs = array('cache', 'upload'))
253
{
254 1
	$md5array_a = generateMD5array($path_a, $ignore_dirs);
255 1
	$md5array_b = generateMD5array($path_b, $ignore_dirs);
256
257 1
	$result = array_diff($md5array_a, $md5array_b);
258
259 1
	return $result;
260
}
261
262
/**
263
 * Function to retrieve all file names of matching pattern in a directory (and it's subdirectories)
264
 * example: getFiles($arr, './modules', '.+/EditView.php/'); // grabs all EditView.phps
265
 * @param array $arr return array to populate matches
266
 * @param string $dir directory to look in [ USE ./ in front of the $dir! ]
267
 * @param regex $pattern optional pattern to match against
268
 */
269
function getFiles(&$arr, $dir, $pattern = null) {
270 2
	if(!is_dir($dir))return;
271 2
 	$d = dir($dir);
272 2
 	while($e =$d->read()){
273 2
 		if(substr($e, 0, 1) == '.')continue;
274 2
 		$file = $dir . '/' . $e;
275 2
 		if(is_dir($file)){
276 2
 			getFiles($arr, $file, $pattern);
277
 		}else{
278 2
 			if(empty($pattern)) $arr[] = $file;
279 2
                else if(preg_match($pattern, $file))
280 2
                $arr[] = $file;
281
 		}
282
 	}
283 2
}
284
285
/**
286
 * Function to split up large files for download
287
 * used in download.php
288
 * @param string $filename
289
 * @param int $retbytes
290
 */
291
function readfile_chunked($filename,$retbytes=true)
292
{
293 1
   	$chunksize = 1*(1024*1024); // how many bytes per chunk
294 1
	$buffer = '';
295 1
	$cnt = 0;
296 1
	$handle = sugar_fopen($filename, 'rb');
297 1
	if ($handle === false)
298
	{
299
	    return false;
300
	}
301 1
	while (!feof($handle))
302
	{
303 1
	    $buffer = fread($handle, $chunksize);
304 1
	    echo $buffer;
305 1
	    flush();
306 1
	    if ($retbytes)
307
	    {
308 1
	        $cnt += strlen($buffer);
309
	    }
310
	}
311 1
	    $status = fclose($handle);
312 1
	if ($retbytes && $status)
313
	{
314 1
	    return $cnt; // return num. bytes delivered like readfile() does.
315
	}
316 1
	return $status;
317
}
318
/**
319
 * Renames a file. If $new_file already exists, it will first unlink it and then rename it.
320
 * used in SugarLogger.php
321
 * @param string $old_filename
322
 * @param string $new_filename
323
 */
324
function sugar_rename( $old_filename, $new_filename){
325 1
	if (empty($old_filename) || empty($new_filename)) return false;
326 1
	$success = false;
327 1
	if(file_exists($new_filename)) {
328
    	unlink($new_filename);
329
    	$success = rename($old_filename, $new_filename);
330
	}
331
	else {
332 1
		$success = rename($old_filename, $new_filename);
333
	}
334
335 1
	return $success;
336
}
337
338
function fileToHash($file){
339 2
		$hash = md5($file);
340 2
		$_SESSION['file2Hash'][$hash] = $file;
341 2
		return $hash;
342
	}
343
344
function hashToFile($hash){
345 1
		if(!empty($_SESSION['file2Hash'][$hash])){
346 1
			return $_SESSION['file2Hash'][$hash];
347
		}
348 1
		return false;
349
}
350
351
352
353
/**
354
 * get_file_extension
355
 * This function returns the file extension portion of a given filename
356
 *
357
 * @param $filename String of filename to return extension
358
 * @param $string_to_lower boolean value indicating whether or not to return value as lowercase, true by default
359
 *
360
 * @return extension String value, blank if no extension found
361
 */
362
function get_file_extension($filename, $string_to_lower=true)
363
{
364 1
    if(strpos($filename, '.') !== false)
365
    {
366 1
       return $string_to_lower ? strtolower(array_pop(explode('.',$filename))) : array_pop(explode('.',$filename));
0 ignored issues
show
explode('.', $filename) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
367
    }
368
369 1
    return '';
370
}
371
372
373
/**
374
 * get_mime_content_type_from_filename
375
 * This function is similar to mime_content_type, but does not require a real
376
 * file or path location.  Instead, the function merely checks the filename
377
 * extension and returns a best guess mime content type.
378
 *
379
 * @param $filename String of filename to return mime content type
380
 * @return mime content type as String value (defaults to 'application/octet-stream' for filenames with extension, empty otherwise)
381
 *
382
 */
383
function get_mime_content_type_from_filename($filename)
384
{
385 1
	if(strpos($filename, '.') !== false)
386
	{
387
        $mime_types = array(
388 1
            'txt' => 'text/plain',
389
            'htm' => 'text/html',
390
            'html' => 'text/html',
391
            'php' => 'text/html',
392
            'css' => 'text/css',
393
            'js' => 'application/javascript',
394
            'json' => 'application/json',
395
            'xml' => 'application/xml',
396
            'swf' => 'application/x-shockwave-flash',
397
            'flv' => 'video/x-flv',
398
399
            // images
400
            'png' => 'image/png',
401
            'jpe' => 'image/jpeg',
402
            'jpeg' => 'image/jpeg',
403
            'jpg' => 'image/jpeg',
404
            'gif' => 'image/gif',
405
            'bmp' => 'image/bmp',
406
            'ico' => 'image/vnd.microsoft.icon',
407
            'tiff' => 'image/tiff',
408
            'tif' => 'image/tiff',
409
            'svg' => 'image/svg+xml',
410
            'svgz' => 'image/svg+xml',
411
412
            // archives
413
            'zip' => 'application/zip',
414
            'rar' => 'application/x-rar-compressed',
415
            'exe' => 'application/x-msdownload',
416
            'msi' => 'application/x-msdownload',
417
            'cab' => 'application/vnd.ms-cab-compressed',
418
419
            // audio/video
420
            'mp3' => 'audio/mpeg',
421
            'qt' => 'video/quicktime',
422
            'mov' => 'video/quicktime',
423
424
            // adobe
425
            'pdf' => 'application/pdf',
426
            'psd' => 'image/vnd.adobe.photoshop',
427
            'ai' => 'application/postscript',
428
            'eps' => 'application/postscript',
429
            'ps' => 'application/postscript',
430
431
            // ms office
432
            'doc' => 'application/msword',
433
            'rtf' => 'application/rtf',
434
            'xls' => 'application/vnd.ms-excel',
435
            'ppt' => 'application/vnd.ms-powerpoint',
436
437
            // open office
438
            'odt' => 'application/vnd.oasis.opendocument.text',
439
            'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
440
        );
441
442 1
        $ext = strtolower(array_pop(explode('.',$filename)));
0 ignored issues
show
explode('.', $filename) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
443 1
        if (array_key_exists($ext, $mime_types)) {
444 1
            return $mime_types[$ext];
445
        }
446
447 1
        return 'application/octet-stream';
448
	}
449
450 1
    return '';
451
}
452
/*
453
function createFTSLogicHook($filePath = 'application/Ext/LogicHooks/logichooks.ext.php')
454
{
455
    $customFileLoc = create_custom_directory($filePath);
456
    $fp = sugar_fopen($customFileLoc, 'wb');
457
    $contents = <<<CIA
458
<?php
459
if (!isset(\$hook_array) || !is_array(\$hook_array)) {
460
    \$hook_array = array();
461
}
462
if (!isset(\$hook_array['after_save']) || !is_array(\$hook_array['after_save'])) {
463
    \$hook_array['after_save'] = array();
464
}
465
\$hook_array['after_save'][] = array(1, 'fts', 'include/SugarSearchEngine/SugarSearchEngineQueueManager.php', 'SugarSearchEngineQueueManager', 'populateIndexQueue');
466
CIA;
467
468
    fwrite($fp,$contents);
469
    fclose($fp);
470
471
}
472
*/
473
function cleanFileName($name)
474
{
475 1
    return preg_replace('/[^\w-._]+/i', '', $name);
476
}
477
478
/**
479
 * Filter dir name to not contain path components - no slashes, no .., etc.
480
 * @param string $name
481
 * @return string
482
 */
483
function cleanDirName($name)
484
{
485 1
    return str_replace(array("\\", "/", "."), "", $name);
486
}
487
488