Sanitize integer option fields - only digits allowed
[squirrelmail.git] / functions / options.php
index 84b8b9ae0e2d29573bd2925bf4bb8d90291bbd10..aef6e97420ec50c6de4b1e8870bb2cab2583c3da 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Functions needed to display the options pages.
  *
- * @copyright © 1999-2007 The SquirrelMail Project Team
+ * @copyright 1999-2011 The SquirrelMail Project Team
  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  * @version $Id$
  * @package squirrelmail
@@ -34,6 +34,11 @@ class SquirrelOption {
      * @var string
      */
     var $caption;
+    /**
+     * Whether or not the caption text is allowed to wrap
+     * @var boolean
+     */
+    var $caption_wrap;
     /**
      * The type of INPUT element
      *
@@ -177,6 +182,7 @@ class SquirrelOption {
         $this->raw_option_array = $raw_option_array;
         $this->name = $name;
         $this->caption = $caption;
+        $this->caption_wrap = TRUE;
         $this->type = $type;
         $this->refresh_level = $refresh_level;
         $this->possible_values = $possible_values;
@@ -207,7 +213,9 @@ class SquirrelOption {
         }
 
         /* Set the default save function. */
-        if (($type != SMOPT_TYPE_HIDDEN) && ($type != SMOPT_TYPE_COMMENT)) {
+        if ($type != SMOPT_TYPE_HIDDEN
+         && $type != SMOPT_TYPE_INFO
+         && $type != SMOPT_TYPE_COMMENT) {
             $this->save_function = SMOPT_SAVE_DEFAULT;
         } else {
             $this->save_function = SMOPT_SAVE_NOOP;
@@ -238,6 +246,14 @@ class SquirrelOption {
         $this->new_value = $new_value;
     }
 
+    /**
+     * Set whether the caption is allowed to wrap for this option.
+     * @param boolean $caption_wrap
+     */
+    function setCaptionWrap($caption_wrap) {
+        $this->caption_wrap = $caption_wrap;
+    }
+
     /**
      * Set the size for this option.
      * @param integer $size
@@ -348,6 +364,9 @@ class SquirrelOption {
 
         /* Get the widget for this option type. */
         switch ($this->type) {
+            case SMOPT_TYPE_PASSWORD:
+                $result = $this->createWidget_String(TRUE);
+                break;
             case SMOPT_TYPE_STRING:
                 $result = $this->createWidget_String();
                 break;
@@ -396,6 +415,9 @@ class SquirrelOption {
             case SMOPT_TYPE_SUBMIT:
                 $result = $this->createWidget_Submit();
                 break;
+            case SMOPT_TYPE_INFO:
+                $result = $this->createWidget_Info();
+                break;
             default:
                 error_box ( 
                     sprintf(_("Option Type '%s' Not Found"), $this->type)
@@ -414,11 +436,25 @@ class SquirrelOption {
         return $result;
     }
 
+    /**
+     * Creates info block
+     * @return string html formated output
+     */
+    function createWidget_Info() {
+        return sq_htmlspecialchars($this->value);
+    }
+
     /**
      * Create string field
+     *
+     * @param boolean $password When TRUE, the text in the input
+     *                          widget will be obscured (OPTIONAL;
+     *                          default = FALSE).
+     *
      * @return string html formated option field
+     *
      */
-    function createWidget_String() {
+    function createWidget_String($password=FALSE) {
         switch ($this->size) {
             case SMOPT_SIZE_TINY:
                 $width = 5;
@@ -437,7 +473,11 @@ class SquirrelOption {
                 $width = 25;
         }
 
-        return addInput('new_' . $this->name, $this->value, $width, 0, $this->aExtraAttribs) . htmlspecialchars($this->trailing_text); 
+//TODO: might be better to have a separate template file for all widgets, because then the layout of the widget and the "trailing text" can be customized - they are still hard coded here
+        if ($password)
+            return addPwField('new_' . $this->name, $this->value, $width, 0, $this->aExtraAttribs) . ' ' . htmlspecialchars($this->trailing_text);
+        else
+            return addInput('new_' . $this->name, $this->value, $width, 0, $this->aExtraAttribs) . ' ' . htmlspecialchars($this->trailing_text);
     }
 
     /**
@@ -791,6 +831,21 @@ function save_option($option) {
         return;
     }
 
+    // if the widget is a selection list, make sure the new
+    // value is actually in the selection list and is not an
+    // injection attack
+    //
+    if ($option->type == SMOPT_TYPE_STRLIST
+     && !array_key_exists($option->new_value, $option->possible_values))
+        return;
+
+
+    // all other widgets except TEXTAREAs should never be allowed to have newlines
+    //
+    else if ($option->type != SMOPT_TYPE_TEXTAREA)
+        $option->new_value = str_replace(array("\r", "\n"), '', $option->new_value);
+
+
     global $data_dir;
 
     // edit lists: first add new elements to list, then
@@ -839,6 +894,15 @@ function save_option($option) {
           && empty($option->new_value)) 
         setPref($data_dir, $username, $option->name, SMPREF_OFF);
 
+    // For integer fields, make sure we only have digits...
+    // We'll be nice and instead of just converting to an integer,
+    // we'll physically remove each non-digit in the string.
+    //
+    else if ($option->type == SMOPT_TYPE_INTEGER) {
+        $option->new_value = preg_replace('/[^0-9]/', '', $option->new_value);
+        setPref($data_dir, $username, $option->name, $option->new_value);
+    }
+
     else
         setPref($data_dir, $username, $option->name, $option->new_value);
 
@@ -910,6 +974,11 @@ function create_option_groups($optgrps, $optvals) {
                     (isset($optset['htmlencoded']) ? $optset['htmlencoded'] : false)
                     );
 
+            /* If provided, set if the caption is allowed to wrap for this option. */
+            if (isset($optset['caption_wrap'])) {
+                $next_option->setCaptionWrap($optset['caption_wrap']);
+            }
+
             /* If provided, set the size for this option. */
             if (isset($optset['size'])) {
                 $next_option->setSize($optset['size']);