CVE-2023-0048: Improper Control of Generation of Code ('Code Injection') (CWE-94)
value: Code Injection in GitHub repository lirantal/daloradius prior to master-branch.
CWE description: The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
CVSS v3 base score: 8.8
Published: 2023-01-04T14:15Z
Repository: https://github.com/lirantal/daloradius
Language: PHP
Files changed: config-backup-managebackups.php, config-logging.php, config-mail.php, css/2.css, library/config_read.php, library/config_write.php, library/validation.php
Commit date: 2023-01-04 13:58:17 +0100
Commit message: Validating/sanitizing user input (#327)

* Better validating log filepath

* improving configuration read/write function

* SMTP configuration parameter validation

* Input validation/sanitization fixes

* minor fix
Diff: diff --git a/config-backup-managebackups.php b/config-backup-managebackups.php
index 7113ffd59..39edb5145 100644
--- a/config-backup-managebackups.php
+++ b/config-backup-managebackups.php
@@ -34,11 +34,33 @@
     include_once("lang/main.php");
     include("library/validation.php");
     include("library/layout.php");
     include_once("include/management/functions.php");
 
-    $file = (array_key_exists('file', $_POST) && isset($_POST['file'])) ? $_POST['file'] : "";
+    // validate path
+    $backup_path_prefix = $configValues['CONFIG_PATH_DALO_VARIABLE_DATA'] . "/backup";
+    $backup_file_suffix = ".sql";
+
+    $file = "";
+    if (array_key_exists('file', $_POST) && !empty(trim($_POST['file']))) {
+        $candidate_backup_file = trim($_POST['file']);
+        
+        if (
+                // this ensures that candidate_backup_file does not contain any ".." sequence
+                strpos($candidate_backup_file, "..") === false &&
+                
+                // this ensures that candidate_backup_file does not contain any "/" char
+                strpos($candidate_backup_file, "/") === false &&
+                
+                // this ensures that candidate_backup_file ends with the backup_file_suffix
+                substr($candidate_backup_file, -strlen($backup_file_suffix)) === $backup_file_suffix
+           ) {
+            
+            $file = $candidate_backup_file;
+        }
+        
+    }
 
     $backupAction = (array_key_exists('action', $_POST) && isset($_POST['action']) &&
                      in_array($_POST['action'], array_keys($valid_backupActions))) ? $_POST['action'] : "";
 
     $cols = array(
@@ -61,19 +83,18 @@
     $orderType = (array_key_exists('orderType', $_GET) && isset($_GET['orderType']) &&
                   in_array(strtolower($_GET['orderType']), array( "desc", "asc" )))
                ? strtolower($_GET['orderType']) : "asc";
 
     // init backup paths
-    $filePath = $configValues['CONFIG_PATH_DALO_VARIABLE_DATA'] . "/backup";
-    $fileName = sprintf("%s/%s", $filePath, $file);
+    $fileName = sprintf("%s/%s", $backup_path_prefix, $file);
     $baseFile = basename($fileName);
     
     if ($_SERVER['REQUEST_METHOD'] === 'POST') {
         
         if (array_key_exists('csrf_token', $_POST) && isset($_POST['csrf_token']) && dalo_check_csrf_token($_POST['csrf_token'])) {
             
-            if (!empty($file) && !empty($backupAction) && is_dir($filePath) && is_readable($fileName)) {
+            if (!empty($file) && !empty($backupAction) && is_dir($backup_path_prefix) && is_readable($fileName)) {
         
                 $fileContents = file_get_contents($fileName);
                 $fileLen = strlen($fileContents);
                 
                 if (!empty($fileContents)) {
@@ -161,10 +182,13 @@
                     $failureMsg = sprintf("Cannot %s backup file %s, please check file availability and permissions",
                                           $backupAction, $baseFile);
                     $logAction .= "$failureMsg on page: ";
                 }
 
+            } else {
+                $failureMsg = sprintf("The requested action cannot be performed");
+                $logAction .= "$failureMsg on page: ";
             }
 
 
         } else {
             // csrf
@@ -189,33 +213,33 @@
     include('include/management/pages_common.php');
     
     // get backup info
     $backupInfo = array();
     
-    if (is_dir($filePath)) {
-        $files = scandir($filePath);
+    if (is_dir($backup_path_prefix)) {
+        $files = scandir($backup_path_prefix);
         if ($orderType == "desc") {
             rsort($files);
         }
     
         $skipList = array( ".", "..", ".svn", ".git" );
-        foreach ($files as $file) {
+        foreach ($files as $this_file) {
             
-            if (in_array($file, $skipList)) {
+            if (in_array($this_file, $skipList)) {
                 continue;
             }
 
-            list($junk, $date, $time) = explode("-", $file);
+            list($junk, $date, $time) = explode("-", $this_file);
             
             $fileDate = substr($date, 0, 4) . "-" . substr($date, 4, 2) . "-" . substr($date, 6, 2);
             $fileTime = substr($time, 0, 2) . ":" . substr($time, 2, 2) . ":" . substr($time, 4, 2);
 
-            $fileSize = filesize($filePath."/".$file);
+            $fileSize = filesize(sprintf("%s/%s", $backup_path_prefix, $this_file));
             
             $backupInfo[] = array(
                                     sprintf("%s, %s", $fileDate, $fileTime),
-                                    $file,
+                                    $this_file,
                                     toxbyte($fileSize),
                                  );
             
         }
     }
diff --git a/config-logging.php b/config-logging.php
index df94868e6..241acb2a5 100644
--- a/config-logging.php
+++ b/config-logging.php
@@ -69,11 +69,11 @@
                         is_dir($log_path_prefix) &&
 
                         // this ensures that candidate_log_file starts with the log_path_prefix
                         substr($candidate_log_file, 0, strlen($log_path_prefix)) === $log_path_prefix &&
                         
-                        // this ensures that candidate_log_file does not contain ".."
+                        // this ensures that candidate_backup_file does not contain any ".." sequence
                         strpos($candidate_log_file, "..") === false &&
                         
                         // this ensures that candidate_log_file ends with the log_file_suffix
                         substr($candidate_log_file, -strlen($log_file_suffix)) === $log_file_suffix &&
                         
diff --git a/config-mail.php b/config-mail.php
index f6f06b210..3fe608452 100644
--- a/config-mail.php
+++ b/config-mail.php
@@ -23,32 +23,84 @@
 
     include ("library/checklogin.php");
     $operator = $_SESSION['operator_user'];
 
     include('library/check_operator_perm.php');
-
     include_once('library/config_read.php');
+    
+    // init logging variables
     $log = "visited page: ";
-
+    $logAction = "";
+    $logDebugSQL = "";
+    
     include_once("lang/main.php");
+    include("library/validation.php");
+    include("library/layout.php");
 
-    if (isset($_REQUEST['submit'])) {
+    $param_label = array(
+                            'CONFIG_MAIL_SMTPADDR' => t('all','SMTPServerAddress'),
+                            'CONFIG_MAIL_SMTPPORT' => t('all','SMTPServerPort'),
+                            'CONFIG_MAIL_SMTPFROM' => t('all','SMTPServerFromEmail'),
+                        );
 
-        if (isset($_REQUEST['config_mail_smtpaddr']))
-            $configValues['CONFIG_MAIL_SMTPADDR'] = $_REQUEST['config_mail_smtpaddr'];
-        
-        if (isset($_REQUEST['config_mail_smtpport']))
-            $configValues['CONFIG_MAIL_SMTPPORT'] = $_REQUEST['config_mail_smtpport'];
-            
-        if (isset($_REQUEST['config_mail_smtp_fromemail']))
-            $configValues['CONFIG_MAIL_SMTPFROM'] = $_REQUEST['config_mail_smtp_fromemail'];
-        
-        include ("library/config_write.php");
-    }    
+    $invalid_input = array();
 
-    include("library/layout.php");
+    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+        if (array_key_exists('csrf_token', $_POST) && isset($_POST['csrf_token']) && dalo_check_csrf_token($_POST['csrf_token'])) {
+            
+            // validate email
+            if (
+                    array_key_exists('CONFIG_MAIL_SMTPFROM', $_POST) &&
+                    !empty(trim($_POST['CONFIG_MAIL_SMTPFROM'])) &&
+                    filter_var(trim($_POST['CONFIG_MAIL_SMTPFROM']), FILTER_VALIDATE_EMAIL)
+               ) {
+                $configValues['CONFIG_MAIL_SMTPFROM'] = trim($_POST['CONFIG_MAIL_SMTPFROM']);
+            } else {
+                $invalid_input['CONFIG_MAIL_SMTPFROM'] = $param_label['CONFIG_MAIL_SMTPFROM'];
+            }
+            
+            // validate port
+            if (
+                    array_key_exists('CONFIG_MAIL_SMTPPORT', $_POST) &&
+                    !empty(trim($_POST['CONFIG_MAIL_SMTPPORT'])) &&
+                    intval(trim($_POST['CONFIG_MAIL_SMTPPORT'])) >= 0 &&
+                    intval(trim($_POST['CONFIG_MAIL_SMTPPORT'])) <= 65535
+               ) {
+                $configValues['CONFIG_MAIL_SMTPPORT'] = intval(trim($_POST['CONFIG_MAIL_SMTPPORT']));
+            } else {
+                $invalid_input['CONFIG_MAIL_SMTPPORT'] = $param_label['CONFIG_MAIL_SMTPPORT'];
+            }
+            
+            // validate ip address/hostname
+            if (
+                    array_key_exists('CONFIG_MAIL_SMTPADDR', $_POST) &&
+                    !empty(trim($_POST['CONFIG_MAIL_SMTPADDR'])) &&
+                    (
+                        preg_match(HOSTNAME_REGEX, trim($_POST['CONFIG_MAIL_SMTPADDR'])) ||
+                        preg_match(IP_REGEX, trim($_POST['CONFIG_MAIL_SMTPADDR']))
+                    )
+               ) {
+                $configValues['CONFIG_MAIL_SMTPADDR'] = trim($_POST['CONFIG_MAIL_SMTPADDR']);
+            } else {
+                $invalid_input['CONFIG_MAIL_SMTPADDR'] = $param_label['CONFIG_MAIL_SMTPADDR'];
+            }
+            
+            if (count($invalid_input) > 0) {
+                $failureMsg = sprintf("Invalid input: [%s]", implode(", ", array_values($invalid_input)));
+                $logAction .= "$failureMsg on page: ";
+            } else {
+                include("library/config_write.php");
+            }
+            
+        } else {
+            // csrf
+            $failureMsg = "CSRF token error";
+            $logAction .= "$failureMsg on page: ";
+        }
+    }
 
+    
     // print HTML prologue
     $title = t('Intro','configmail.php');
     $help = t('helpPage','configmail');
     
     print_html_prologue($title, $langCode);
@@ -58,52 +110,68 @@
     echo '<div id="contentnorightbar">';
     print_title_and_help($title, $help);
     
     include_once('include/management/actionMessages.php');
 
-?>
-
-<form name="mailsettings" method="POST">
-    <fieldset>
-        <h302><?= t('title','Settings'); ?></h302>
-        
-        <br/>
-
-        <ul>
-
-            <li class="fieldset">
-                <label for="config_mail_smtpaddr" class="form"><?= t('all','SMTPServerAddress') ?></label>
-                <input type="text" value="<?= $configValues['CONFIG_MAIL_SMTPADDR'] ?>" name="config_mail_smtpaddr">
-            </li>
+    $fieldset0_descriptor = array(
+                                    "title" => t('title','Settings')
+                                 );
 
-            <li class="fieldset">
-                <label for="config_mail_smtpport" class="form"><?= t('all','SMTPServerPort') ?></label>
-                <input type="number" min="0" max="65535" value="<?= $configValues['CONFIG_MAIL_SMTPPORT'] ?>" name="config_mail_smtpport">
-            </li>
-
-            <li class="fieldset">
-                <label for="config_mail_smtp_fromemail" class="form"><?= t('all','SMTPServerFromEmail') ?></label>
-                <input type="text" value="<?= $configValues['CONFIG_MAIL_SMTPFROM'] ?>" name="config_mail_smtp_fromemail">
-            </li>
-
-
-            <li class="fieldset">
-                <br/><hr><br/>
-                <input type="submit" name="submit" value="<?= t('buttons','apply') ?>" class="button">
-            </li>
-        </ul>
-    </fieldset>
-</form>
-
-        </div><!-- #contentnorightbar -->
-        
-        <div id="footer">
-<?php
+    $input_descriptors0 = array();
+    
+    
+    $input_descriptors0[] = array(
+                                        "type" => "text",
+                                        "caption" => t('all','SMTPServerAddress'),
+                                        "name" => 'CONFIG_MAIL_SMTPADDR',
+                                        "value" => (!array_key_exists('CONFIG_MAIL_SMTPADDR', $invalid_input)
+                                                    ? $configValues['CONFIG_MAIL_SMTPADDR'] : "")
+                                     );
+    
+    $input_descriptors0[] = array(
+                                        "type" => "number",
+                                        "caption" => t('all','SMTPServerPort'),
+                                        "name" => 'CONFIG_MAIL_SMTPPORT',
+                                        "value" => (!array_key_exists('CONFIG_MAIL_SMTPPORT', $invalid_input)
+                                                    ? $configValues['CONFIG_MAIL_SMTPPORT'] : ""),
+                                        "min" => 0,
+                                        "max" => 65535
+                                 );
+    
+    $input_descriptors0[] = array(
+                                        "type" => "email",
+                                        "caption" => t('all','SMTPServerFromEmail'),
+                                        "name" => 'CONFIG_MAIL_SMTPFROM',
+                                        "value" => (!array_key_exists('CONFIG_MAIL_SMTPFROM', $invalid_input)
+                                                    ? $configValues['CONFIG_MAIL_SMTPFROM'] : ""),
+                                     );
+    
+    $input_descriptors0[] = array(
+                                    "name" => "csrf_token",
+                                    "type" => "hidden",
+                                    "value" => dalo_csrf_token(),
+                                 );
+
+    $input_descriptors0[] = array(
+                                    'type' => 'submit',
+                                    'name' => 'submit',
+                                    'value' => t('buttons','apply')
+                                 );
+
+    open_form();
+    
+    // open 0-th fieldset
+    open_fieldset($fieldset0_descriptor);
+    
+    foreach ($input_descriptors0 as $input_descriptor) {
+        print_form_component($input_descriptor);
+    }
+    
+    close_fieldset();
+    
+    close_form();
+    
     include('include/config/logging.php');
-    include('page-footer.php');
-?>
-        </div><!-- #footer -->
-    </div>
-</div>
+    
+    print_footer_and_html_epilogue();
 
-</body>
-</html>
+?>
diff --git a/css/2.css b/css/2.css
index 20cc272b6..014f1f311 100644
--- a/css/2.css
+++ b/css/2.css
@@ -360,11 +360,11 @@ fieldset textarea {
     box-sizing: content-box;
 }
 
 fieldset input[type=text], fieldset input[type=number],
 fieldset input[type=date], fieldset input[type=password],
-fieldset select {
+fieldset input[type=email], fieldset select {
     padding: 5px;
     margin: 4px;
     border: 1px solid var(--rich-black);
     border-radius: 3px;
     resize: vertical;
@@ -381,11 +381,11 @@ fieldset select {
     box-sizing: content-box;
 }
 
 fieldset input[type=text]:disabled, fieldset input[type=numer]:disabled,
 fieldset input[type=date]:disabled, fieldset input[type=password]:disabled,
-fieldset select:disabled {
+fieldset input[type=email]:disabled, fieldset select:disabled {
     background-color: #eeeeee;
     border: 1px solid gray;
 }
 
 #sidebar select:hover, #sidebar select:focus, #sidebar input:hover, #sidebar input:focus {
diff --git a/library/config_read.php b/library/config_read.php
index 4014799ec..726573842 100644
--- a/library/config_read.php
+++ b/library/config_read.php
@@ -12,42 +12,34 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
  *********************************************************************************************************
- * Description:
- * 		reads configuration file from daloradius.conf and appends it to the $configValues associated array
  *
- * Authors:	Liran Tal <liran@enginx.com>
+ * Description:    reads configuration file from daloradius.conf.php and
+ *                 loads its contents to the $configValues associated array
+ *
+ * Authors:        Liran Tal <liran@enginx.com>
+ *                 Filippo Lauria <filippo.lauria@iit.cnr.it>
  *
  *********************************************************************************************************
  */
- 
-$_configFile = dirname(__FILE__).'/daloradius.conf.php';
-include($_configFile);
 
-/*
-****************************************************************************************************
-* deprecated for handling the configuration variables as a PHP page for the sake of security
-****************************************************************************************************
-$_configCommentChar = "#";
+// prevent this file to be directly accessed
+if (strpos($_SERVER['PHP_SELF'], '/library/config_read.php') !== false) {
+    header("Location: ../index.php");
+    exit;
+}
+
+$_configFile = dirname(__FILE__) . '/daloradius.conf.php';
+include($_configFile);
 
-$_configFp = fopen($_configFile, "r");
-if ($_configFp) {
-	while (!feof($_configFp)) {
-		$_configLine = trim(fgets($_configFp));
-		if ($_configLine && !ereg("^$_configCommentChar", $_configLine)) {
-			$_configPieces = explode("=", $_configLine);
-			$_configOption = trim($_configPieces[0]);
-			$_configValue = trim($_configPieces[1]);
-			$configValues[$_configOption] = $_configValue;
-		}
-	}
-	fclose($_configFp);
-} else {
-	$failureMsg = "Could not open the file for reading:<b> $_configFile </b>
-	<br/>Check file permissions. The file should be readable by the webserver's user/group";
+// strip slashes (if any)
+foreach ($configValues as $_configOption => $_configElem) {
+    if (is_array($_configElem)) {
+        continue;
+    }
+    
+    $configValues[$_configOption] = stripslashes($_configElem);
 }
-****************************************************************************************************
-*/
 
 ?>
diff --git a/library/config_write.php b/library/config_write.php
index 9bedbb891..aaaa257e7 100644
--- a/library/config_write.php
+++ b/library/config_write.php
@@ -12,61 +12,95 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
  *********************************************************************************************************
- * Description:
- * 		writes configuration information from the $configValues array to daloradius.conf
  *
- * Authors:	Liran Tal <liran@enginx.com>
+ * Description:    writes configuration information from the $configValues array
+ *                 to the daloradius.conf.php configuration file
+ * 
+ * Authors:        Liran Tal <liran@enginx.com>
+ *                 Filippo Lauria <filippo.lauria@iit.cnr.it>
  *
  *********************************************************************************************************
  */
 
-$configFile = dirname(__FILE__).'/daloradius.conf.php';
+// prevent this file to be directly accessed
+if (strpos($_SERVER['PHP_SELF'], '/library/config_write.php') !== false) {
+    header("Location: ../index.php");
+    exit;
+}
+
+// useful variables
+$configFile = dirname(__FILE__) . '/daloradius.conf.php';
 $date = date("D M j G:i:s T Y");
 
-$fp = fopen($configFile, "w");
-if ($fp) {
-	fwrite($fp, 
-		"<?php\n".
-		"/*\n".
-		" *********************************************************************************************************\n".
-		" * daloRADIUS - RADIUS Web Platform\n".
-		" * Copyright (C) 2007 - Liran Tal <liran@enginx.com> All Rights Reserved.\n".
-		" *\n".
-		" * This program is free software; you can redistribute it and/or\n".
-		" * modify it under the terms of the GNU General Public License\n".
-		" * as published by the Free Software Foundation; either version 2\n".
-		" * of the License, or (at your option) any later version.\n".
-		" *\n".
-		" * You should have received a copy of the GNU General Public License\n".
-		" * along with this program; if not, write to the Free Software\n".
-		" * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n".
-		" *\n".
-		" *********************************************************************************************************\n".
-		" * Description:\n".
-		" *              daloRADIUS Configuration File\n".
-		" *\n".
-		" * Modification Date:\n".
-		" *              $date\n".
-		" *********************************************************************************************************\n".
-		" */\n".
-		"\n\n");
-	foreach ($configValues as $_configOption => $_configElem) {
-		if (is_array($configValues[$_configOption])) {
-			$var = "\$configValues['" . $_configOption . "'] = \t\t";
-			$var .= var_export($configValues[$_configOption], true);
-			$var .= ";\n";
-			fwrite($fp, $var);
-		} else
-	        fwrite($fp, "\$configValues['" . $_configOption . "'] = '" . $configValues[$_configOption] . "';\n");
-	}
-	fwrite($fp, "\n\n?>");
-	fclose($fp);
-	$successMsg = "Updated database settings for configuration file";
-} else {
-	$failureMsg = "Could not open the file for writing: <b>$configFile</b>
-	<br/>Check file permissions. The file should be writable by the webserver's user/group";
+//
+// generating file contents
+//
+
+// 1. open
+$fileContents = <<<EOL
+<?php
+/*
+ *********************************************************************************************************
+ * daloRADIUS - RADIUS Web Platform
+ * Copyright (C) 2007 - Liran Tal <liran@enginx.com> All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *********************************************************************************************************
+ * 
+ * Description:          daloRADIUS Configuration File
+ *
+ * Modification Date:    {$date}
+ *
+ *********************************************************************************************************
+ */
+
+// prevent this file to be directly accessed
+if (strpos(\$_SERVER['PHP_SELF'], '/library/daloradius.conf.php') !== false) {
+    header("Location: ../index.php");
+    exit;
+}
+
+
+EOL;
+
+// 2. body
+foreach ($configValues as $_configOption => $_configElem) {
+    $fileContents .= sprintf("\$configValues['%s'] =", $_configOption);
+    
+    if (is_array($configValues[$_configOption])) {
+        $fileContents .= str_repeat(" ", 8) . sprintf("%s;\n", var_export($configValues[$_configOption], true));
+    } else {
+        $fileContents .= sprintf(" '%s';\n", addslashes($configValues[$_configOption]));
+    }
 }
 
+// 3. close
+$fileContents .= <<<EOL
+
+?>
+
+EOL;
+
+//
+// putting contents into file
+//
+$writtenBytes = intval(file_put_contents($configFile, $fileContents));
+
+if ($writtenBytes > 0) {
+    $successMsg = "Configuration file has been successfully updated";
+} else {
+    $failureMsg = sprintf("Could not open the file for writing: <strong>%s</strong>", $configFile)
+                . "<br>Check file permissions. The file should be writable by the webserver's user/group";
+} 
+
 ?>
diff --git a/library/validation.php b/library/validation.php
index b8f83fb7f..601fdb131 100644
--- a/library/validation.php
+++ b/library/validation.php
@@ -27,10 +27,11 @@ if (strpos($_SERVER['PHP_SELF'], '/library/validation.php') !== false) {
 }
 
 // commonly used regexes collection
 define("DATE_REGEX", '/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/');
 define("ORDER_TYPE_REGEX", '/^(de|a)sc$/');
+define("HOSTNAME_REGEX", '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/');
 define("IP_REGEX", '/^(((2(5[0-5]|[0-4][0-9]))|1[0-9]{2}|[1-9]?[0-9]).){3}((2(5[0-5]|[0-4][0-9]))|1[0-9]{2}|[1-9]?[0-9])$/');
 define("NETMASK_LENGTH_REGEX", '/^3[0-2]|[1-2][0-9]|[1-9]$/');
 define("MACADDR_REGEX", '/^(?:[0-9A-Fa-f]{2}([-:]))(?:[0-9A-Fa-f]{2}\1){4}[0-9A-Fa-f]{2}$/');
 define("PINCODE_REGEX", '/^[a-zA-Z0-9]+$/');
 

Vulnerable code:     $file = (array_key_exists('file', $_POST) && isset($_POST['file'])) ? $_POST['file'] : "";
    $filePath = $configValues['CONFIG_PATH_DALO_VARIABLE_DATA'] . "/backup";
    $fileName = sprintf("%s/%s", $filePath, $file);
            if (!empty($file) && !empty($backupAction) && is_dir($filePath) && is_readable($fileName)) {
    if (is_dir($filePath)) {
        $files = scandir($filePath);
        foreach ($files as $file) {
            if (in_array($file, $skipList)) {
            list($junk, $date, $time) = explode("-", $file);
            $fileSize = filesize($filePath."/".$file);
                                    $file,
                        // this ensures that candidate_log_file does not contain ".."


    if (isset($_REQUEST['submit'])) {
        if (isset($_REQUEST['config_mail_smtpaddr']))
            $configValues['CONFIG_MAIL_SMTPADDR'] = $_REQUEST['config_mail_smtpaddr'];
        
        if (isset($_REQUEST['config_mail_smtpport']))
            $configValues['CONFIG_MAIL_SMTPPORT'] = $_REQUEST['config_mail_smtpport'];
            
        if (isset($_REQUEST['config_mail_smtp_fromemail']))
            $configValues['CONFIG_MAIL_SMTPFROM'] = $_REQUEST['config_mail_smtp_fromemail'];
        
        include ("library/config_write.php");
    }    
    include("library/layout.php");
?>

<form name="mailsettings" method="POST">
    <fieldset>
        <h302><?= t('title','Settings'); ?></h302>
        
        <br/>

        <ul>

            <li class="fieldset">
                <label for="config_mail_smtpaddr" class="form"><?= t('all','SMTPServerAddress') ?></label>
                <input type="text" value="<?= $configValues['CONFIG_MAIL_SMTPADDR'] ?>" name="config_mail_smtpaddr">
            </li>
            <li class="fieldset">
                <label for="config_mail_smtpport" class="form"><?= t('all','SMTPServerPort') ?></label>
                <input type="number" min="0" max="65535" value="<?= $configValues['CONFIG_MAIL_SMTPPORT'] ?>" name="config_mail_smtpport">
            </li>

            <li class="fieldset">
                <label for="config_mail_smtp_fromemail" class="form"><?= t('all','SMTPServerFromEmail') ?></label>
                <input type="text" value="<?= $configValues['CONFIG_MAIL_SMTPFROM'] ?>" name="config_mail_smtp_fromemail">
            </li>


            <li class="fieldset">
                <br/><hr><br/>
                <input type="submit" name="submit" value="<?= t('buttons','apply') ?>" class="button">
            </li>
        </ul>
    </fieldset>
</form>

        </div><!-- #contentnorightbar -->
        
        <div id="footer">
<?php
    include('page-footer.php');
?>
        </div><!-- #footer -->
    </div>
</div>
</body>
</html>
fieldset select {
fieldset select:disabled {
 * Description:
 * 		reads configuration file from daloradius.conf and appends it to the $configValues associated array
 * Authors:	Liran Tal <liran@enginx.com>
 
$_configFile = dirname(__FILE__).'/daloradius.conf.php';
include($_configFile);
/*
****************************************************************************************************
* deprecated for handling the configuration variables as a PHP page for the sake of security
****************************************************************************************************
$_configCommentChar = "#";
$_configFp = fopen($_configFile, "r");
if ($_configFp) {
	while (!feof($_configFp)) {
		$_configLine = trim(fgets($_configFp));
		if ($_configLine && !ereg("^$_configCommentChar", $_configLine)) {
			$_configPieces = explode("=", $_configLine);
			$_configOption = trim($_configPieces[0]);
			$_configValue = trim($_configPieces[1]);
			$configValues[$_configOption] = $_configValue;
		}
	}
	fclose($_configFp);
} else {
	$failureMsg = "Could not open the file for reading:<b> $_configFile </b>
	<br/>Check file permissions. The file should be readable by the webserver's user/group";
****************************************************************************************************
*/
 * Description:
 * 		writes configuration information from the $configValues array to daloradius.conf
 * Authors:	Liran Tal <liran@enginx.com>
$configFile = dirname(__FILE__).'/daloradius.conf.php';
$fp = fopen($configFile, "w");
if ($fp) {
	fwrite($fp, 
		"<?php\n".
		"/*\n".
		" *********************************************************************************************************\n".
		" * daloRADIUS - RADIUS Web Platform\n".
		" * Copyright (C) 2007 - Liran Tal <liran@enginx.com> All Rights Reserved.\n".
		" *\n".
		" * This program is free software; you can redistribute it and/or\n".
		" * modify it under the terms of the GNU General Public License\n".
		" * as published by the Free Software Foundation; either version 2\n".
		" * of the License, or (at your option) any later version.\n".
		" *\n".
		" * You should have received a copy of the GNU General Public License\n".
		" * along with this program; if not, write to the Free Software\n".
		" * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n".
		" *\n".
		" *********************************************************************************************************\n".
		" * Description:\n".
		" *              daloRADIUS Configuration File\n".
		" *\n".
		" * Modification Date:\n".
		" *              $date\n".
		" *********************************************************************************************************\n".
		" */\n".
		"\n\n");
	foreach ($configValues as $_configOption => $_configElem) {
		if (is_array($configValues[$_configOption])) {
			$var = "\$configValues['" . $_configOption . "'] = \t\t";
			$var .= var_export($configValues[$_configOption], true);
			$var .= ";\n";
			fwrite($fp, $var);
		} else
	        fwrite($fp, "\$configValues['" . $_configOption . "'] = '" . $configValues[$_configOption] . "';\n");
	}
	fwrite($fp, "\n\n?>");
	fclose($fp);
	$successMsg = "Updated database settings for configuration file";
} else {
	$failureMsg = "Could not open the file for writing: <b>$configFile</b>
	<br/>Check file permissions. The file should be writable by the webserver's user/group";
Fixed code:     // validate path
    $backup_path_prefix = $configValues['CONFIG_PATH_DALO_VARIABLE_DATA'] . "/backup";
    $backup_file_suffix = ".sql";

    $file = "";
    if (array_key_exists('file', $_POST) && !empty(trim($_POST['file']))) {
        $candidate_backup_file = trim($_POST['file']);
        
        if (
                // this ensures that candidate_backup_file does not contain any ".." sequence
                strpos($candidate_backup_file, "..") === false &&
                
                // this ensures that candidate_backup_file does not contain any "/" char
                strpos($candidate_backup_file, "/") === false &&
                
                // this ensures that candidate_backup_file ends with the backup_file_suffix
                substr($candidate_backup_file, -strlen($backup_file_suffix)) === $backup_file_suffix
           ) {
            
            $file = $candidate_backup_file;
        }
        
    }
    $fileName = sprintf("%s/%s", $backup_path_prefix, $file);
            if (!empty($file) && !empty($backupAction) && is_dir($backup_path_prefix) && is_readable($fileName)) {
            } else {
                $failureMsg = sprintf("The requested action cannot be performed");
                $logAction .= "$failureMsg on page: ";
    if (is_dir($backup_path_prefix)) {
        $files = scandir($backup_path_prefix);
        foreach ($files as $this_file) {
            if (in_array($this_file, $skipList)) {
            list($junk, $date, $time) = explode("-", $this_file);
            $fileSize = filesize(sprintf("%s/%s", $backup_path_prefix, $this_file));
                                    $this_file,
                        // this ensures that candidate_backup_file does not contain any ".." sequence
    
    // init logging variables
    $logAction = "";
    $logDebugSQL = "";
    
    include("library/validation.php");
    include("library/layout.php");
    $param_label = array(
                            'CONFIG_MAIL_SMTPADDR' => t('all','SMTPServerAddress'),
                            'CONFIG_MAIL_SMTPPORT' => t('all','SMTPServerPort'),
                            'CONFIG_MAIL_SMTPFROM' => t('all','SMTPServerFromEmail'),
                        );
    $invalid_input = array();
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (array_key_exists('csrf_token', $_POST) && isset($_POST['csrf_token']) && dalo_check_csrf_token($_POST['csrf_token'])) {
            
            // validate email
            if (
                    array_key_exists('CONFIG_MAIL_SMTPFROM', $_POST) &&
                    !empty(trim($_POST['CONFIG_MAIL_SMTPFROM'])) &&
                    filter_var(trim($_POST['CONFIG_MAIL_SMTPFROM']), FILTER_VALIDATE_EMAIL)
               ) {
                $configValues['CONFIG_MAIL_SMTPFROM'] = trim($_POST['CONFIG_MAIL_SMTPFROM']);
            } else {
                $invalid_input['CONFIG_MAIL_SMTPFROM'] = $param_label['CONFIG_MAIL_SMTPFROM'];
            }
            
            // validate port
            if (
                    array_key_exists('CONFIG_MAIL_SMTPPORT', $_POST) &&
                    !empty(trim($_POST['CONFIG_MAIL_SMTPPORT'])) &&
                    intval(trim($_POST['CONFIG_MAIL_SMTPPORT'])) >= 0 &&
                    intval(trim($_POST['CONFIG_MAIL_SMTPPORT'])) <= 65535
               ) {
                $configValues['CONFIG_MAIL_SMTPPORT'] = intval(trim($_POST['CONFIG_MAIL_SMTPPORT']));
            } else {
                $invalid_input['CONFIG_MAIL_SMTPPORT'] = $param_label['CONFIG_MAIL_SMTPPORT'];
            }
            
            // validate ip address/hostname
            if (
                    array_key_exists('CONFIG_MAIL_SMTPADDR', $_POST) &&
                    !empty(trim($_POST['CONFIG_MAIL_SMTPADDR'])) &&
                    (
                        preg_match(HOSTNAME_REGEX, trim($_POST['CONFIG_MAIL_SMTPADDR'])) ||
                        preg_match(IP_REGEX, trim($_POST['CONFIG_MAIL_SMTPADDR']))
                    )
               ) {
                $configValues['CONFIG_MAIL_SMTPADDR'] = trim($_POST['CONFIG_MAIL_SMTPADDR']);
            } else {
                $invalid_input['CONFIG_MAIL_SMTPADDR'] = $param_label['CONFIG_MAIL_SMTPADDR'];
            }
            
            if (count($invalid_input) > 0) {
                $failureMsg = sprintf("Invalid input: [%s]", implode(", ", array_values($invalid_input)));
                $logAction .= "$failureMsg on page: ";
            } else {
                include("library/config_write.php");
            }
            
        } else {
            // csrf
            $failureMsg = "CSRF token error";
            $logAction .= "$failureMsg on page: ";
        }
    }
    
    $fieldset0_descriptor = array(
                                    "title" => t('title','Settings')
                                 );
    $input_descriptors0 = array();
    
    
    $input_descriptors0[] = array(
                                        "type" => "text",
                                        "caption" => t('all','SMTPServerAddress'),
                                        "name" => 'CONFIG_MAIL_SMTPADDR',
                                        "value" => (!array_key_exists('CONFIG_MAIL_SMTPADDR', $invalid_input)
                                                    ? $configValues['CONFIG_MAIL_SMTPADDR'] : "")
                                     );
    
    $input_descriptors0[] = array(
                                        "type" => "number",
                                        "caption" => t('all','SMTPServerPort'),
                                        "name" => 'CONFIG_MAIL_SMTPPORT',
                                        "value" => (!array_key_exists('CONFIG_MAIL_SMTPPORT', $invalid_input)
                                                    ? $configValues['CONFIG_MAIL_SMTPPORT'] : ""),
                                        "min" => 0,
                                        "max" => 65535
                                 );
    
    $input_descriptors0[] = array(
                                        "type" => "email",
                                        "caption" => t('all','SMTPServerFromEmail'),
                                        "name" => 'CONFIG_MAIL_SMTPFROM',
                                        "value" => (!array_key_exists('CONFIG_MAIL_SMTPFROM', $invalid_input)
                                                    ? $configValues['CONFIG_MAIL_SMTPFROM'] : ""),
                                     );
    
    $input_descriptors0[] = array(
                                    "name" => "csrf_token",
                                    "type" => "hidden",
                                    "value" => dalo_csrf_token(),
                                 );

    $input_descriptors0[] = array(
                                    'type' => 'submit',
                                    'name' => 'submit',
                                    'value' => t('buttons','apply')
                                 );

    open_form();
    
    // open 0-th fieldset
    open_fieldset($fieldset0_descriptor);
    
    foreach ($input_descriptors0 as $input_descriptor) {
        print_form_component($input_descriptor);
    }
    
    close_fieldset();
    
    close_form();
    
    
    print_footer_and_html_epilogue();
?>
fieldset input[type=email], fieldset select {
fieldset input[type=email]:disabled, fieldset select:disabled {
 * Description:    reads configuration file from daloradius.conf.php and
 *                 loads its contents to the $configValues associated array
 *
 * Authors:        Liran Tal <liran@enginx.com>
 *                 Filippo Lauria <filippo.lauria@iit.cnr.it>
// prevent this file to be directly accessed
if (strpos($_SERVER['PHP_SELF'], '/library/config_read.php') !== false) {
    header("Location: ../index.php");
    exit;
}

$_configFile = dirname(__FILE__) . '/daloradius.conf.php';
include($_configFile);
// strip slashes (if any)
foreach ($configValues as $_configOption => $_configElem) {
    if (is_array($_configElem)) {
        continue;
    }
    
    $configValues[$_configOption] = stripslashes($_configElem);
 * Description:    writes configuration information from the $configValues array
 *                 to the daloradius.conf.php configuration file
 * 
 * Authors:        Liran Tal <liran@enginx.com>
 *                 Filippo Lauria <filippo.lauria@iit.cnr.it>
// prevent this file to be directly accessed
if (strpos($_SERVER['PHP_SELF'], '/library/config_write.php') !== false) {
    header("Location: ../index.php");
    exit;
}

// useful variables
$configFile = dirname(__FILE__) . '/daloradius.conf.php';
//
// generating file contents
//

// 1. open
$fileContents = <<<EOL
<?php
/*
 *********************************************************************************************************
 * daloRADIUS - RADIUS Web Platform
 * Copyright (C) 2007 - Liran Tal <liran@enginx.com> All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *********************************************************************************************************
 * 
 * Description:          daloRADIUS Configuration File
 *
 * Modification Date:    {$date}
 *
 *********************************************************************************************************
 */

// prevent this file to be directly accessed
if (strpos(\$_SERVER['PHP_SELF'], '/library/daloradius.conf.php') !== false) {
    header("Location: ../index.php");
    exit;
}


EOL;

// 2. body
foreach ($configValues as $_configOption => $_configElem) {
    $fileContents .= sprintf("\$configValues['%s'] =", $_configOption);
    
    if (is_array($configValues[$_configOption])) {
        $fileContents .= str_repeat(" ", 8) . sprintf("%s;\n", var_export($configValues[$_configOption], true));
    } else {
        $fileContents .= sprintf(" '%s';\n", addslashes($configValues[$_configOption]));
    }
// 3. close
$fileContents .= <<<EOL

?>

EOL;

//
// putting contents into file
//
$writtenBytes = intval(file_put_contents($configFile, $fileContents));

if ($writtenBytes > 0) {
    $successMsg = "Configuration file has been successfully updated";
} else {
    $failureMsg = sprintf("Could not open the file for writing: <strong>%s</strong>", $configFile)
                . "<br>Check file permissions. The file should be writable by the webserver's user/group";
} 

define("HOSTNAME_REGEX", '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/');