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.

ModuleBuilder/parsers/parser.modifylayoutview.php (1 issue)

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)
3
die('Not A Valid Entry Point');
4
/*********************************************************************************
5
 * SugarCRM Community Edition is a customer relationship management program developed by
6
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
7
8
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
9
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
10
 *
11
 * This program is free software; you can redistribute it and/or modify it under
12
 * the terms of the GNU Affero General Public License version 3 as published by the
13
 * Free Software Foundation with the addition of the following permission added
14
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
15
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
16
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
17
 *
18
 * This program is distributed in the hope that it will be useful, but WITHOUT
19
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
21
 * details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License along with
24
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
25
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26
 * 02110-1301 USA.
27
 *
28
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
29
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
30
 *
31
 * The interactive user interfaces in modified source and object code versions
32
 * of this program must display Appropriate Legal Notices, as required under
33
 * Section 5 of the GNU Affero General Public License version 3.
34
 *
35
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
36
 * these Appropriate Legal Notices must retain the display of the "Powered by
37
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
38
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
39
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
40
 ********************************************************************************/
41
42
43
require_once ('modules/ModuleBuilder/parsers/ModuleBuilderParser.php');
44
45
class ParserModifyLayoutView extends ModuleBuilderParser
46
{
47
48
    var $maxColumns; // number of columns in this layout
49
    var $usingWorkingFile = false; // if a working file exists (used by view.edit.php among others to determine the title for the layout edit panel)
50
    var $language_module; // set to module name for studio, passed to the smarty template and used by sugar_translate
51
    var $_sourceFile; // private - the source of the layout defn
52
    var $_customFile; // private
53
    var $_workingFile; // private
54
    var $_originalFile; //private
55
    var $_moduleVariable; // private - if set, contains the name of the variable containing the module name in the $viewdef file
56
    var $_module; // private
57
    var $_view; // private
58
    var $_viewdefs; // private
59
    var $_fieldDefs; // private
60
61
62
    /**
63
     * Constructor
64
     */
65
    function init ($module, $view, $submittedLayout = false)
66
    {
67
        $this->_view = ucfirst($view);
68
        $this->_module = $module;
69
        $this->language_module = $module;
70
71
        $this->_baseDirectory = "modules/{$module}/metadata/";
72
        $file =  $this->_baseDirectory . strtolower($view) . "defs.php";
73
        $this->_customFile = "custom/" . $file;
74
        $this->_workingFile = "custom/working/" . $file;
75
76
        $this->_sourceView = $this->_view;
77
        $this->_originalFile = $file ;
78
        $this->_sourceFile = $file;
79
        if (is_file($this->_workingFile))
80
        {
81
            $this->_sourceFile = $this->_workingFile;
82
            $this->usingWorkingFile = true;
83
        }
84
        else if (is_file($this->_customFile))
85
        {
86
            $this->_sourceFile = $this->_customFile;
87
        }
88
        else if (! is_file($this->_sourceFile))
89
        {
90
            // if we don't have ANY defined metadata then improvise as best we can
91
            if (strtolower($this->_view) == 'quickcreate')
92
            {
93
                // special handling for quickcreates - base the quickcreate on the editview if no quickcreatedef exists
94
                $this->_sourceFile = $this->_baseDirectory."editviewdefs.php";
95
                if (is_file("custom/" . $this->_sourceFile))
96
                {
97
                    $this->_sourceFile = "custom/" . $this->_sourceFile;
98
                }
99
                $this->_sourceView = 'EditView';
100
            }
101
            else
102
            {
103
                $this->_fatalError('parser.modifylayout.php->init(): no metadata for '.$this->_module.' '.$this->_view);
104
            }
105
        }
106
107
        // get the fieldDefs from the bean
108
        $class = $GLOBALS ['beanList'] [$module];
109
        require_once ($GLOBALS ['beanFiles'] [$class]);
110
        $bean = new $class();
111
        $this->_fieldDefs = & $bean->field_defs;
112
113
        $this->loadModule($this->_module, $this->_sourceView);
114
        $this->_viewdefs ['panels'] = $this->_parseData($this->_viewdefs['panels']); // put into a canonical format
115
        $this->maxColumns = $this->_viewdefs ['templateMeta'] ['maxColumns'];
116
117
        if ($submittedLayout)
118
        {
119
            // replace the definitions with the new submitted layout
120
            $this->_loadLayoutFromRequest();
121
        } else
122
        {
123
            $this->_padFields(); // destined for a View, so we want to add in (empty) fields
124
        }
125
//      $GLOBALS['log']->debug($this->_viewdefs['panels']);
126
127
    }
128
129
    function getAvailableFields ()
130
    {
131
        // Available fields are those that are in the Model and the original layout definition, but not already shown in the View
132
        // So, because the formats of the two are different we brute force loop through View and unset the fields we find in a copy of Model
133
        $availableFields = $this->_getModelFields();
134
        $GLOBALS['log']->debug( get_class($this)."->getAvailableFields(): _getModelFields returns: ".implode(",",array_keys($availableFields)));
135
        if (! empty($this->_viewdefs))
136
        {
137
            foreach ($this->_viewdefs ['panels'] as $panel)
138
            {
139
                foreach ($panel as $row)
140
                {
141
                    foreach ($row as $fieldArray)
142
                    { // fieldArray is an array('name'=>name,'label'=>label)
143
                        if (isset($fieldArray ['name']))
144
                        {
145
                            unset($availableFields [$fieldArray ['name']]);
146
                            $GLOBALS['log']->debug( get_class($this)."->getAvailableFields(): removing ".$fieldArray ['name'] );
147
                        }
148
                    }
149
                }
150
            }
151
        }
152
        return $availableFields;
153
    }
154
155
    function getLayout ()
156
    {
157
        return $this->_viewdefs ['panels'];
158
    }
159
160
    function writeWorkingFile ()
161
    {
162
        $this->_writeToFile($this->_workingFile,$this->_view,$this->_module,$this->_viewdefs,$this->_variables);
163
    }
164
165
    function handleSave ()
166
    {
167
        $this->_writeToFile($this->_customFile,$this->_view,$this->_module,$this->_viewdefs,$this->_variables);
168
        // now clear the cache so that the results are immediately visible
169
        include_once('include/TemplateHandler/TemplateHandler.php');
170
        if (strtolower($this->_view) == 'quickcreate')
171
        {
172
        	TemplateHandler::clearCache($this->_module,"form_SubPanelQuickCreate_{$this->_module}.tpl");
173
        	TemplateHandler::clearCache($this->_module,"form_DCQuickCreate_{$this->_module}.tpl");
174
        } 
175
        else 
176
        {
177
        	TemplateHandler::clearCache($this->_module,"{$this->_view}.tpl");
178
        }
179
180
    }
181
182
    function loadModule ($module, $view)
183
    {
184
        $this->_viewdefs = array();
185
        $viewdefs = null;
186
187
        $loaded = $this->_loadFromFile($view,$this->_sourceFile,$module);
188
        $this->_viewdefs = $loaded['viewdefs'][$module][$view];
189
        $this->_variables = $loaded['variables'];
190
    }
191
192
    /**
193
     * Load the canonical panel layout from the submitted form
194
     *
195
     */
196
    function _loadLayoutFromRequest ()
197
    {
198
199
        $i = 1;
200
        // set up the map of panel# (as provided in the _REQUEST) to panel ID (as used in $this->_viewdefs['panels'])
201
        foreach ($this->_viewdefs ['panels'] as $panelID => $panel)
202
        {
203
            $panelMap [$i ++] = $panelID;
204
        }
205
        // replace any old values with new panel labels from the request
206
        foreach ($_REQUEST as $key => $value)
207
        {
208
            $components = explode('-', $key);
209
            if ($components [0] == 'panel')
210
            {
211
                $panelMap [$components ['1']] = $value;
212
            }
213
        }
214
215
        $olddefs = $this->_viewdefs ['panels'];
216
        $origFieldDefs = $this->_getOrigFieldViewDefs();
217
//      $GLOBALS['log']->debug('origFieldDefs');
218
//      $GLOBALS['log']->debug($origFieldDefs);
219
        $this->_viewdefs ['panels'] = null; // because the new field properties should replace the old fields, not be merged
220
221
        if ($this->maxColumns < 1)
222
        {
223
            $this->_fatalError("EditDetailViewParser:invalid maxColumns=" . $this->maxColumns);
224
        }
225
226
        foreach ($_REQUEST as $slot => $value)
227
        {
228
            $slotComponents = explode('-', $slot); // [0] = 'slot', [1] = panel #, [2] = slot #, [3] = property name
229
            if ($slotComponents [0] == 'slot')
230
            {
231
                $slotNumber = $slotComponents ['2'];
232
                $panelID = $panelMap [$slotComponents ['1']];
233
                $rowID = floor($slotNumber / $this->maxColumns);
234
                $colID = $slotNumber - ($rowID * $this->maxColumns);
235
                //If the original editview defined this field, copy that over.
236
                if ($slotComponents ['3'] == 'name' && isset($origFieldDefs [$value]) && is_array($origFieldDefs [$value]))
237
                {
238
                    $this->_viewdefs ['panels'] [$panelID] [$rowID] [$colID] = $origFieldDefs [$value];
239
                }
240
                else
241
                {
242
                    $property = $slotComponents ['3'];
243
                    if ($value == '(filler)')
244
                    {
245
                        $this->_viewdefs ['panels'] [$panelID] [$rowID] [$colID] = NULL;
246
                    } else
247
                    {
248
                        $this->_viewdefs ['panels'] [$panelID] [$rowID] [$colID] [$property] = $value;
249
                    }
250
                }
251
            }
252
        }
253
254
        // Now handle the (empty) fields - first non-(empty) field goes in at column 0; all other (empty)'s removed
255
        // Do this AFTER reading in all the $_REQUEST parameters as can't guarantee the order of those, and we need to operate on complete rows
256
        foreach ($this->_viewdefs ['panels'] as $panelID => $panel)
0 ignored issues
show
The expression $this->_viewdefs['panels'] of type null is not traversable.
Loading history...
257
        {
258
            // remove all (empty)s
259
            foreach ($panel as $rowID => $row)
260
            {
261
                $startOfRow = true;
262
                $offset = 0;
263
                foreach ($row as $colID => $col)
264
                {
265
                    if ($col ['name'] == '(empty)')
266
                    {
267
                        // if a leading (empty) then remove (by noting that remaining fields need to be shuffled along)
268
                        if ($startOfRow)
269
                        {
270
                            $offset ++;
271
                        }
272
                        unset($row [$colID]);
273
                    } else
274
                    {
275
                        $startOfRow = false;
276
                    }
277
                }
278
                // reindex to remove leading (empty)s
279
                $newRow = array();
280
                foreach ($row as $colID => $col)
281
                {
282
                    $newRow [$colID - $offset] = $col;
283
                }
284
                $this->_viewdefs ['panels'] [$panelID] [$rowID] = $newRow;
285
            }
286
        }
287
        //          _pp($this->_viewdefs);
288
    }
289
290
    function _padFields ()
291
    {
292
        if (! empty($this->_viewdefs))
293
        {
294
            foreach ($this->_viewdefs ['panels'] as $panelID => $panel)
295
            {
296
                $column = 0;
297
                foreach ($panel as $rowID => $row)
298
                {
299
                    // pad between fields on a row
300
                    foreach ($row as $colID => $col)
301
                    {
302
                        for ($i = $column + 1 ; $i < $colID ; $i ++ )
303
                        {
304
                            $row [$i] = array('name' => '(empty)', 'label' => '(empty)');
305
                        }
306
                        $column = $colID;
307
                    }
308
                    // now pad out to the end of the row
309
                    if (($column + 1) < $this->maxColumns)
310
                    { // last column is maxColumns-1
311
                        for ($i = $column + 1 ; $i < $this->maxColumns ; $i ++ )
312
                        {
313
                            $row [$i] = array('name' => '(empty)', 'label' => '(empty)');
314
                        }
315
                    }
316
                    ksort($row);
317
                    $this->_viewdefs ['panels'] [$panelID] [$rowID] = $row;
318
                }
319
            }
320
        }
321
    }
322
323
324
    // add a new field to the end of a panel
325
    // don't write out (caller should call handleSave() when ready)
326
    function _addField ($properties, $panelID = FALSE)
327
    {
328
329
        // if a panelID was not passed, use the first available panel in the list
330
        if (!$panelID) {
331
            $panels = array_keys($this->_viewdefs['panels']);
332
            $panelID = $panels[0];
333
        }
334
335
        if (isset($this->_viewdefs ['panels'] [$panelID]))
336
        {
337
338
            // need to clean up the viewdefs before writing them -- Smarty will fail if any fillers/empties are present
339
            foreach ($this->_viewdefs['panels'] as $loop_panelID => $panel_contents) {
340
                foreach ($panel_contents as $row_id => $row) {
341
                    foreach ($row as $col_id => $col) {
342
                        if ($col['name'] == '(filler)') {
343
                            $this->_viewdefs['panels'][$loop_panelID][$row_id][$col_id] = NULL;
344
                        }
345
                        elseif ($col['name'] == '(empty)') {
346
                            unset($this->_viewdefs['panels'][$loop_panelID][$row_id][$col_id]);
347
                        }
348
                    }
349
                }
350
            }
351
352
            $panel = $this->_viewdefs ['panels'] [$panelID];
353
            $lastrow = count($panel) - 1; // index starts at 0
354
            $lastcol = count($panel [$lastrow]);
355
356
            // if we're on the last column of the last row, start a new row
357
            //          print "lastrow=$lastrow lastcol=$lastcol";
358
            if ($lastcol >= $this->maxColumns)
359
            {
360
                $lastrow ++;
361
                $this->_viewdefs ['panels'] [$panelID] [$lastrow] = array();
362
                $lastcol = 0;
363
            }
364
365
            $this->_viewdefs ['panels'] [$panelID] [$lastrow] [$lastcol] = $properties;
366
        }
367
    }
368
369
    /* getModelFields returns an array of all fields stored in the database for this module plus those fields in the original layout definition (so we get fields such as Team ID)*/
370
    function _getModelFields ()
371
    {
372
        $modelFields = array();
373
        $origViewDefs = $this->_getOrigFieldViewDefs();
374
//        $GLOBALS['log']->debug("Original viewdefs = ".print_r($origViewDefs,true));
375
        foreach ($origViewDefs as $field => $def)
376
        {
377
            if (!empty($field))
378
            {
379
                if (! is_array($def)) {
380
                    $def = array('name' => $field);
381
                }
382
                // get this field's label - if it has not been explicitly provided, see if the fieldDefs has a label for this field, and if not fallback to the field name
383
                if (! isset($def ['label']))
384
                        {
385
                            if (! empty($this->_fieldDefs [$field] ['vname']))
386
                            {
387
                                $def ['label'] = $this->_fieldDefs [$field] ['vname'];
388
                            } else
389
                            {
390
                                $def ['label'] = $field;
391
                            }
392
                        }
393
                $modelFields[$field] = array('name' => $field, 'label' => $def ['label']);
394
            }
395
        }
396
        $GLOBALS['log']->debug(print_r($modelFields,true));
397
        foreach ($this->_fieldDefs as $field => $def)
398
        {
399
            if ((!empty($def['studio']) && $def['studio'] == 'visible')
400
            || (empty($def['studio']) &&  (empty($def ['source']) || $def ['source'] == 'db' || $def ['source'] == 'custom_fields') && $def ['type'] != 'id' && strcmp($field, 'deleted') != 0 && (empty($def ['dbType']) || $def ['dbType'] != 'id') && (empty($def ['dbtype']) || $def ['dbtype'] != 'id')))
401
            {
402
                $label = isset($def['vname']) ? $def['vname'] : $def['name'];
403
                $modelFields [$field] = array('name' => $field, 'label' => $label);
404
            }
405
            else
406
            {
407
                $GLOBALS['log']->debug( get_class($this)."->_getModelFields(): skipping $field from modelFields as it fails the test for inclusion");
408
            }
409
        }
410
        $GLOBALS['log']->debug( get_class($this)."->_getModelFields(): remaining entries in modelFields are: ".implode(",",array_keys($modelFields)));
411
        return $modelFields;
412
    }
413
414
    function _parseData ($panels)
415
    {
416
        $fields = array();
417
        if (empty($panels))
418
        return;
419
420
        // Fix for a flexibility in the format of the panel sections - if only one panel, then we don't have a panel level defined, it goes straight into rows
421
        // See EditView2 for similar treatment
422
        if (! empty($panels) && count($panels) > 0)
423
        {
424
            $keys = array_keys($panels);
425
            if (is_numeric($keys [0]))
426
            {
427
                $defaultPanel = $panels;
428
                unset($panels); //blow away current value
429
                $panels [''] = $defaultPanel;
430
            }
431
        }
432
433
        foreach ($panels as $panelID => $panel)
434
        {
435
            foreach ($panel as $rowID => $row)
436
            {
437
                foreach ($row as $colID => $col)
438
                {
439
                    $properties = array();
440
441
                    if (! empty($col))
442
                    {
443
                        if (is_string($col))
444
                        {
445
                            $properties ['name'] = $col;
446
                        } else if (! empty($col ['name']))
447
                        {
448
                            $properties = $col;
449
                        }
450
                    } else
451
                    {
452
                        $properties ['name'] = translate('LBL_FILLER');
453
                    }
454
455
                    if (! empty($properties ['name']))
456
                    {
457
458
                        // get this field's label - if it has not been explicity provided, see if the fieldDefs has a label for this field, and if not fallback to the field name
459
                        if (! isset($properties ['label']))
460
                        {
461
                            if (! empty($this->_fieldDefs [$properties ['name']] ['vname']))
462
                            {
463
                                $properties ['label'] = $this->_fieldDefs [$properties ['name']] ['vname'];
464
                            } else
465
                            {
466
                                $properties ['label'] = $properties ['name'];
467
                            }
468
                        }
469
470
                        $displayData[strtoupper($panelID)] [$rowID] [$colID] = $properties;
471
472
                    }
473
                }
474
            }
475
        }
476
        return $displayData;
477
    }
478
479
    function _getOrigFieldViewDefs ()
480
    {
481
        $origFieldDefs = array();
482
        $GLOBALS['log']->debug("Original File = ".$this->_originalFile);
483
        if (file_exists($this->_originalFile))
484
        {
485
            include ($this->_originalFile);
486
            $origdefs = $viewdefs [$this->_module] [$this->_sourceView] ['panels'];
487
//          $GLOBALS['log']->debug($origdefs);
488
            // Fix for a flexibility in the format of the panel sections - if only one panel, then we don't have a panel level defined, it goes straight into rows
489
            // See EditView2 for similar treatment
490
            if (! empty($origdefs) && count($origdefs) > 0)
491
            {
492
                $keys = array_keys($origdefs);
493
                if (is_numeric($keys [0]))
494
                {
495
                    $defaultPanel = $origdefs;
496
                    unset($origdefs); //blow away current value
497
                    $origdefs [''] = $defaultPanel;
498
                }
499
            }
500
            foreach ($origdefs as $pname => $paneldef)
501
            {
502
                foreach ($paneldef as $row)
503
                {
504
                    foreach ($row as $fieldDef)
505
                    {
506
                        if (is_array($fieldDef))
507
                        {
508
                            $fieldName = $fieldDef ['name'];
509
                        }
510
                        else
511
                        {
512
                            $fieldName = $fieldDef;
513
                        }
514
                        $origFieldDefs [$fieldName] = $fieldDef;
515
                    }
516
                }
517
            }
518
        }
519
520
        return $origFieldDefs;
521
    }
522
523
}
524
?>