Prechádzať zdrojové kódy

adding database field size checks (#1233721)

tokul 20 rokov pred
rodič
commit
d5cd5f3d3a

+ 32 - 4
config/conf.pl

@@ -360,6 +360,9 @@ $abook_global_file_listing = 'true'     if ( !$abook_global_file_listing );
 $encode_header_key = ''                 if ( !$encode_header_key );
 $hide_auth_header = 'false'             if ( !$hide_auth_header );
 $time_zone_type = '0'                   if ( !$time_zone_type );
+$prefs_user_size = 128                  if ( !$prefs_user_size );
+$prefs_key_size = 64                    if ( !$prefs_key_size );
+$prefs_val_size = 65536                 if ( !$prefs_val_size );
 
 if ( $ARGV[0] eq '--install-plugin' ) {
     print "Activating plugin " . $ARGV[1] . "\n";
@@ -608,9 +611,9 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) && ( $command ne ":q" ) ) {
         print "\n";
         print "3.  DSN for Preferences    : $WHT$prefs_dsn$NRM\n";
         print "4.  Table for Preferences  : $WHT$prefs_table$NRM\n";
-        print "5.  Field for username     : $WHT$prefs_user_field$NRM\n";
-        print "6.  Field for prefs key    : $WHT$prefs_key_field$NRM\n";
-        print "7.  Field for prefs value  : $WHT$prefs_val_field$NRM\n";
+        print "5.  Field for username     : $WHT$prefs_user_field$NRM ($prefs_user_size)\n";
+        print "6.  Field for prefs key    : $WHT$prefs_key_field$NRM ($prefs_key_size)\n";
+        print "7.  Field for prefs value  : $WHT$prefs_val_field$NRM ($prefs_val_size)\n";
         print "\n";
         print "8.  DSN for Global Address Book            : $WHT$addrbook_global_dsn$NRM\n";
         print "9.  Table for Global Address Book          : $WHT$addrbook_global_table$NRM\n";
@@ -2964,6 +2967,7 @@ sub command95 {
     } else {
         $new_field =~ s/[\r\n]//g;
     }
+    $prefs_user_size = db_pref_size($prefs_user_size);
     return $new_field;
 }
 
@@ -2978,6 +2982,7 @@ sub command96 {
     } else {
         $new_field =~ s/[\r\n]//g;
     }
+    $prefs_key_size = db_pref_size($prefs_key_size);
     return $new_field;
 }
 
@@ -2992,9 +2997,26 @@ sub command97 {
     } else {
         $new_field =~ s/[\r\n]//g;
     }
+    $prefs_val_size = db_pref_size($prefs_val_size);
     return $new_field;
 }
 
+# routine is used to set database field limits
+# it needs one argument
+sub db_pref_size() {
+    my ($size) = $_[0];
+    print "\nDatabase fields have size limits.\n";
+    print "\n";
+    print "What limit is set for this field? [$WHT$size$NRM]: $WHT";
+    $new_size = <STDIN>;
+    if ( $new_size eq "\n" ) {
+        $new_size = $size;
+    } else {
+        $new_size =~ s/[\r\n]//g;
+    }
+    return $new_size;
+}
+
 sub command98 {
     print "If you want to store your global address book in a database then\n";
     print "you need to set this DSN to a valid value. The format for this is:\n";
@@ -3583,10 +3605,16 @@ sub save_data {
         print CF "\$prefs_table = '$prefs_table';\n";
     # string
         print CF "\$prefs_user_field = '$prefs_user_field';\n";
+    # integer
+        print CF "\$prefs_user_size = $prefs_user_size;\n";
     # string
         print CF "\$prefs_key_field = '$prefs_key_field';\n";
+    # integer
+        print CF "\$prefs_key_size = $prefs_key_size;\n";
     # string
-        print CF "\$prefs_val_field = '$prefs_val_field';\n\n";
+        print CF "\$prefs_val_field = '$prefs_val_field';\n";
+    # integer
+        print CF "\$prefs_val_size = $prefs_val_size;\n\n";
     # string
         print CF "\$addrbook_global_dsn = '$addrbook_global_dsn';\n";
     # string

+ 30 - 0
config/config_default.php

@@ -845,9 +845,39 @@ $addrbook_table = 'address';
  */
 $prefs_dsn = '';
 $prefs_table = 'userprefs';
+/**
+ * Preference key field 
+ * @global string $prefs_key_field
+ */
 $prefs_key_field = 'prefkey';
+/**
+ * Size of preference key field
+ * @global integer $prefs_key_size
+ * @since 1.5.1
+ */
+$prefs_key_size = 64;
+/**
+ * Preference owner field 
+ * @global string $prefs_user_field
+ */
 $prefs_user_field = 'user';
+/**
+ * Size of preference owner field
+ * @global integer $prefs_user_size
+ * @since 1.5.1
+ */
+$prefs_user_size = 128;
+/**
+ * Preference value field 
+ * @global string $prefs_val_field
+ */
 $prefs_val_field = 'prefval';
+/**
+ * Size of preference key field
+ * @global integer $prefs_val_size
+ * @since 1.5.1
+ */
+$prefs_val_size = 65536;
 
 /*** Global sql database options ***/
 /**

+ 21 - 0
doc/db-backend.txt

@@ -118,3 +118,24 @@ database.
 
 Default preferences can be set by altering the $default array in
 db_prefs.php.
+
+Troubleshooting
+---------------
+1. Oversized field values. Preferences are not/can't be saved
+
+Database fields have size limits. Preference table example sets 128 
+character limit to owner field, 64 character limit to preference key 
+field and 64KB (database BLOB field size) limit to value field.
+
+If interface tries to insert data without checking field limits, it
+can cause data loss or database errors. Table information functions
+provided by Pear DB libraries are not accurate and some database 
+backends don't support them. Since 1.5.1 SquirrelMail provides
+configuration options that set allowed field sizes.
+
+If you see oversized field errors in your error logs - check your 
+database structure. Issue can be solved by increasing database field 
+sizes.
+
+If you want to get more debugging information - check setKey() function 
+in dbPrefs class. Class is stored in functions/db_prefs.php

+ 69 - 0
functions/db_prefs.php

@@ -142,6 +142,25 @@ class dbPrefs {
     var $default = Array('theme_default' => 0,
                          'show_html_default' => '0');
 
+    /**
+     * Preference owner field size
+     * @var integer
+     * @since 1.5.1
+     */
+    var $user_size = 128;
+    /**
+     * Preference key field size
+     * @var integer
+     * @since 1.5.1
+     */
+    var $key_size = 64;
+    /**
+     * Preference value field size
+     * @var integer
+     * @since 1.5.1
+     */
+    var $val_size = 65536;
+
     /**
      * initialize DB connection object
      * @return boolean true, if object is initialized
@@ -149,6 +168,7 @@ class dbPrefs {
     function open() {
         global $prefs_dsn, $prefs_table;
         global $prefs_user_field, $prefs_key_field, $prefs_val_field;
+        global $prefs_user_size, $prefs_key_size, $prefs_val_size;
 
         if(isset($this->dbh)) {
             return true;
@@ -172,6 +192,15 @@ class dbPrefs {
         if (!empty($prefs_val_field)) {
             $this->val_field = $prefs_val_field;
         }
+        if (!empty($prefs_user_size)) {
+            $this->user_size = (int) $prefs_user_size;
+        }
+        if (!empty($prefs_key_size)) {
+            $this->key_size = (int) $prefs_key_size;
+        }
+        if (!empty($prefs_val_size)) {
+            $this->val_size = (int) $prefs_val_size;
+        }
         $dbh = DB::connect($prefs_dsn, true);
 
         if(DB::isError($dbh)) {
@@ -261,6 +290,46 @@ class dbPrefs {
         if (!$this->open()) {
             return false;
         }
+
+        /**
+         * Check if username fits into db field
+         */
+        if (strlen($user) > $this->user_size) {
+            $this->error = "Oversized username value."
+                ." User's preferences can't be saved. See doc/db-backend.txt troubleshooting documentation.";
+
+            /**
+             * Debugging function. Can be used to log all issues that trigger 
+             * oversized field errors. Function should be enabled in all three 
+             * strlen checks. See http://www.php.net/error-log
+             */
+            // error_log($user.'|'.$key.'|'.$value."\n",3,'/tmp/oversized_log');
+
+            // error is fatal
+            $this->failQuery(null);
+        }
+        /**
+         * Check if preference key fits into db field
+         */
+        if (strlen($key) > $this->key_size) {
+            $err_msg = "Oversized user's preference key."
+                ." Some user preferences are not saved. See doc/db-backend.txt troubleshooting documentation.";
+            // error is not fatal. Only some preference is not saved.
+            trigger_error($err_msg,E_USER_WARNING);
+            return false;
+        }
+        /**
+         * Check if preference value fits into db field
+         */
+        if (strlen($value) > $this->val_size) {
+            $err_msg = "Oversized user's preference value."
+                ." Some user preferences are not saved. See doc/db-backend.txt troubleshooting documentation.";
+            // error is not fatal. Only some preference is not saved.
+            trigger_error($err_msg,E_USER_WARNING);
+            return false;
+        }
+
+
         if ($this->db_type == SMDB_MYSQL) {
             $query = sprintf("REPLACE INTO %s (%s, %s, %s) ".
                              "VALUES('%s','%s','%s')",

+ 6 - 0
plugins/administrator/defines.php

@@ -289,14 +289,20 @@ $defcfg = array( '$config_version' => array( 'name' => _("Config File Version"),
                                               'type' => SMOPT_TYPE_STRING,
                                               'size' => 40,
                                               'default' => 'user' ),
+                 '$prefs_user_size' => array( 'name' => _("Size of username field"),
+                                              'type' => SMOPT_TYPE_INTEGER ),
                  '$prefs_key_field' => array('name' => _("Preferences key field"),
                                              'type' => SMOPT_TYPE_STRING,
                                              'size' => 40,
                                              'default' => 'prefkey' ),
+                 '$prefs_key_size' => array( 'name' => _("Size of key field"),
+                                             'type' => SMOPT_TYPE_INTEGER ),
                  '$prefs_val_field' => array('name' => _("Preferences value field"),
                                              'type' => SMOPT_TYPE_STRING,
                                              'size' => 40,
                                              'default' => 'prefval' ),
+                 '$prefs_val_size' => array( 'name' => _("Size of value field"),
+                                             'type' => SMOPT_TYPE_INTEGER ),
                  '$addrbook_global_dsn' => array( 'name' => _("Global address book DSN"),
                                            'type' => SMOPT_TYPE_STRING,
                                            'size' => 40 ),