List:Commits« Previous MessageNext Message »
From:Ashish Agarwal Date:April 30 2012 6:36am
Subject:bzr push into mysql-trunk branch (ashish.y.agarwal:3879 to 3880)
View as plain text  
 3880 Ashish Agarwal	2012-04-30
      WL2739: Including password validation on multiple
              character set. 

    modified:
      include/mysql/plugin_validate_password.h
      mysql-test/r/validate_password_plugin.result
      mysql-test/t/validate_password_plugin.test
      plugin/password_validation/validate_password.cc
      sql/item_func.cc
      sql/item_strfunc.cc
      sql/sql_acl.cc
      sql/sql_acl.h
      sql/sql_plugin.h
      sql/sql_yacc.yy
 3879 Ashish Agarwal	2012-04-24
      wl2739: Build failure in windows and some additional changes.

    modified:
      plugin/password_validation/validate_password.cc
      sql/sql_plugin.h
=== modified file 'include/mysql/plugin_validate_password.h'
--- a/include/mysql/plugin_validate_password.h	2012-04-24 11:58:02 +0000
+++ b/include/mysql/plugin_validate_password.h	2012-04-30 06:36:01 +0000
@@ -20,6 +20,7 @@
 #define MYSQL_PLUGIN_VALIDATE_PASSWORD_INCLUDED
 
 #include <mysql/plugin.h>
+#include <sql_string.h>
 
 #define MYSQL_VALIDATE_PASSWORD_INTERFACE_VERSION 0x0100
 
@@ -36,11 +37,11 @@ struct st_mysql_validate_password
     policy (as choosen by plugin variable) and FALSE for all other
     password
   */
-  bool (*validate_password)(const char *password);
+  bool (*validate_password)(String *password);
   /**
     This function returns the highest policy number which the password
     satisfy.
   */
-  uint (*validate_password_strength)(const char *password);
+  uint (*validate_password_strength)(String *password);
 };
 #endif

=== modified file 'mysql-test/r/validate_password_plugin.result'
--- a/mysql-test/r/validate_password_plugin.result	2012-04-23 15:41:09 +0000
+++ b/mysql-test/r/validate_password_plugin.result	2012-04-30 06:36:01 +0000
@@ -1,10 +1,11 @@
+CALL mtr.add_suppression("dictionary file not found");
+CALL mtr.add_suppression("dictionary file size too large");
 CREATE USER 'base_user'@'localhost' IDENTIFIED BY '';
 INSTALL PLUGIN validate_password SONAME 'validate_password.so';
 INSTALL PLUGIN validate_password SONAME 'validate_password.so';
 ERROR HY000: Function 'validate_password' already exists
-policy: low= 1, medium= 2, strong= 3
-password policy low (which only check for password length)
-default case: password length should be minimum 8
+# password policy low (which only check for password length)
+# default case: password length should be minimum 8
 SET @@global.validate_password_policy_number= 1;
 CREATE USER 'user'@'localhost' IDENTIFIED BY '';
 ERROR HY000: not a valid password ''
@@ -14,8 +15,8 @@ UPDATE mysql.user SET PASSWORD= PASSWORD
 ERROR HY000: not a valid password 'password'
 GRANT USAGE ON *.* TO 'base_user'@'localhost' IDENTIFIED BY 'password1234';
 SET @@global.validate_password_length= 8;
-password policy medium (check for mixed_case, digits, special_chars)
-default case : atleast 1 mixed_case, 1 digit, 1 special_char
+# password policy medium (check for mixed_case, digits, special_chars)
+# default case : atleast 1 mixed_case, 1 digit, 1 special_char
 SET @@global.validate_password_policy_number= 2;
 CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
 ERROR HY000: not a valid password 'password'
@@ -41,9 +42,9 @@ SET @@global.validate_password_policy_nu
 CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
 ERROR HY000: not a valid password 'password'
 SET PASSWORD FOR 'base_user'@'localhost'= PASSWORD('password1A#');
-ERROR HY000: not a valid password 'password1A#'
+ERROR HY000: not a valid password 'password1a#'
 UPDATE mysql.user SET PASSWORD= PASSWORD('pass12345A#') WHERE user='base_user';
-ERROR HY000: not a valid password 'pass12345A#'
+ERROR HY000: not a valid password 'pass12345a#'
 GRANT USAGE ON *.* TO 'base_user'@'localhost' IDENTIFIED BY 'PA12wrd!#';
 # test for password_validate_strength function
 SELECT VALIDATE_PASSWORD_STRENGTH('password', 0);
@@ -51,9 +52,11 @@ ERROR 42000: Incorrect parameter count i
 SELECT VALIDATE_PASSWORD_STRENGTH();
 ERROR 42000: Incorrect parameter count in the call to native function 'VALIDATE_PASSWORD_STRENGTH'
 SELECT VALIDATE_PASSWORD_STRENGTH('');
-ERROR HY000: not a valid password ''
+VALIDATE_PASSWORD_STRENGTH('')
+0
 SELECT VALIDATE_PASSWORD_STRENGTH('pass');
-ERROR HY000: not a valid password 'pass'
+VALIDATE_PASSWORD_STRENGTH('pass')
+0
 SELECT VALIDATE_PASSWORD_STRENGTH('password');
 VALIDATE_PASSWORD_STRENGTH('password')
 1
@@ -63,5 +66,20 @@ VALIDATE_PASSWORD_STRENGTH('password1A#'
 SELECT VALIDATE_PASSWORD_STRENGTH('PA12wrd!#');
 VALIDATE_PASSWORD_STRENGTH('PA12wrd!#')
 3
+SET NAMES 'ujis';
+SELECT VALIDATE_PASSWORD_STRENGTH('PA12wrd!#');
+VALIDATE_PASSWORD_STRENGTH('PA12wrd!#')
+3
+UNINSTALL PLUGIN validate_password;
+# restarting the server with no dictionary file.
+# Restart server.
+INSTALL PLUGIN validate_password SONAME 'validate_password.so';
+SET @@global.validate_password_policy_number= 3;
+# same password was not accepted as it was present in the dictionary file
+SET PASSWORD FOR 'base_user'@'localhost'= PASSWORD('password1A#');
+# As no dictionary file is present password strength is 3
+SELECT VALIDATE_PASSWORD_STRENGTH('password1A#');
+VALIDATE_PASSWORD_STRENGTH('password1A#')
+3
 DROP USER 'base_user'@'localhost';
 UNINSTALL PLUGIN validate_password;

=== modified file 'mysql-test/t/validate_password_plugin.test'
--- a/mysql-test/t/validate_password_plugin.test	2012-04-23 15:41:09 +0000
+++ b/mysql-test/t/validate_password_plugin.test	2012-04-30 06:36:01 +0000
@@ -1,5 +1,7 @@
 --source include/not_embedded.inc
 --source include/have_validate_password_plugin.inc
+CALL mtr.add_suppression("dictionary file not found");
+CALL mtr.add_suppression("dictionary file size too large");
 
 CREATE USER 'base_user'@'localhost' IDENTIFIED BY '';
 --replace_regex /\.dll/.so/
@@ -8,10 +10,10 @@ eval INSTALL PLUGIN validate_password SO
 eval INSTALL PLUGIN validate_password SONAME '$VALIDATE_PASSWORD';
 
 # test for all the three password policy
---echo policy: low= 1, medium= 2, strong= 3
+# policy: low= 1, medium= 2, strong= 3
 
---echo password policy low (which only check for password length)
---echo default case: password length should be minimum 8
+--echo # password policy low (which only check for password length)
+--echo # default case: password length should be minimum 8
 
 SET @@global.validate_password_policy_number= 1;
 --error ER_NOT_VALID_PASSWORD
@@ -23,8 +25,8 @@ UPDATE mysql.user SET PASSWORD= PASSWORD
 GRANT USAGE ON *.* TO 'base_user'@'localhost' IDENTIFIED BY 'password1234';
 SET @@global.validate_password_length= 8;
 
---echo password policy medium (check for mixed_case, digits, special_chars)
---echo default case : atleast 1 mixed_case, 1 digit, 1 special_char
+--echo # password policy medium (check for mixed_case, digits, special_chars)
+--echo # default case : atleast 1 mixed_case, 1 digit, 1 special_char
 
 SET @@global.validate_password_policy_number= 2;
 --error ER_NOT_VALID_PASSWORD
@@ -59,19 +61,59 @@ SET PASSWORD FOR 'base_user'@'localhost'
 UPDATE mysql.user SET PASSWORD= PASSWORD('pass12345A#') WHERE user='base_user';
 GRANT USAGE ON *.* TO 'base_user'@'localhost' IDENTIFIED BY 'PA12wrd!#';
 
+
 --echo # test for password_validate_strength function
 
 --error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
 SELECT VALIDATE_PASSWORD_STRENGTH('password', 0);
 --error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
 SELECT VALIDATE_PASSWORD_STRENGTH();
---error ER_NOT_VALID_PASSWORD
 SELECT VALIDATE_PASSWORD_STRENGTH('');
---error ER_NOT_VALID_PASSWORD
 SELECT VALIDATE_PASSWORD_STRENGTH('pass');
 SELECT VALIDATE_PASSWORD_STRENGTH('password');
 SELECT VALIDATE_PASSWORD_STRENGTH('password1A#');
 SELECT VALIDATE_PASSWORD_STRENGTH('PA12wrd!#');
 
+# Multibyte character set that have greater size when converted
+# from uppercase to lowercase.
+
+SET NAMES 'ujis';
+SELECT VALIDATE_PASSWORD_STRENGTH('PA12wrd!#');
+
+UNINSTALL PLUGIN validate_password;
+
+--echo # restarting the server with no dictionary file.
+
+# Write file to make mysql-test-run.pl wait for the server to stop
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+
+# Request shutdown
+-- send_shutdown
+
+# Call script that will poll the server waiting for it to disapear
+-- source include/wait_until_disconnected.inc
+
+--echo # Restart server.
+--exec echo "restart:--loose-validate_password_dictionary_file='NO'" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+
+# Turn on reconnect
+--enable_reconnect
+
+# Call script that will poll the server waiting for it to be back online again
+--source include/wait_until_connected_again.inc
+
+# Turn off reconnect again
+--disable_reconnect
+
+--replace_regex /\.dll/.so/
+eval INSTALL PLUGIN validate_password SONAME '$VALIDATE_PASSWORD';
+
+SET @@global.validate_password_policy_number= 3;
+--echo # same password was not accepted as it was present in the dictionary file
+SET PASSWORD FOR 'base_user'@'localhost'= PASSWORD('password1A#');
+
+--echo # As no dictionary file is present password strength is 3
+SELECT VALIDATE_PASSWORD_STRENGTH('password1A#');
+
 DROP USER 'base_user'@'localhost';
 UNINSTALL PLUGIN validate_password;

=== modified file 'plugin/password_validation/validate_password.cc'
--- a/plugin/password_validation/validate_password.cc	2012-04-24 15:36:30 +0000
+++ b/plugin/password_validation/validate_password.cc	2012-04-30 06:36:01 +0000
@@ -14,23 +14,22 @@
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
 
 #include <m_ctype.h>
-#include <cctype>
-#include <algorithm>
 #include <string>
 #include <mysql/plugin_validate_password.h>
 #include <set>
-#include <iostream>
+#include <iostream>         /* dictionary file read       */
 #include <fstream>
-#include "sql_plugin.h"
+#include "sql_plugin.h"     /* for opt_plugin_dir         */
+#include "log.h"            /* for warning                */
 
 #define MAX_DICTIONARY_FILE_LENGTH 1024 * 1024
-#define MIN_DICTIONARY_WORD_LENGTH 3
+#define MIN_DICTIONARY_WORD_LENGTH 4
 
 enum PASSWORD_POLICY { PASSWORD_STRENGTH_REJECTED, PASSWORD_STRENGTH_LOW,
                        PASSWORD_STRENGTH_MEDIUM, PASSWORD_STRENGTH_STRONG };
 
 typedef std::string string_type;
-typedef std::set<std::string> set_type;
+typedef std::set<string_type> set_type;
 set_type dictionary_words;
 
 static uint validate_password_length;
@@ -40,63 +39,83 @@ static uint validate_password_special_ch
 static uint validate_password_policy_number;
 static char *validate_password_dictionary_file;
 
-static bool validate_dictionary_check(const char *password)
+static bool validate_dictionary_check(String *password)
 {
-  string_type password_str(password);
+  const CHARSET_INFO *cs= password->charset();
+  String tmp_password_str;
+  if (cs->casedn_multiply == 1)
+  {
+    uint len;
+    len= cs->cset->casedn(cs, (char*) password->ptr(), password->length(),
+                              (char*) password->ptr(), password->length());
+    password->length(len);
+  }
+  else
+  {
+    uint len= password->length() * cs->casedn_multiply;
+    tmp_password_str.alloc(len);
+    tmp_password_str.set_charset(cs);
+    len= cs->cset->casedn(cs, (char*) password->ptr(), password->length(),
+                              (char*) tmp_password_str.ptr(), len);
+    tmp_password_str.length(len);
+    password= &tmp_password_str;
+  }
+  uint substr_pos= 0;
+  uint substr_length= password->length();
+  string_type password_str(password->ptr());
   string_type password_substr;
   set_type::iterator itr;
-  uint password_length= strlen(password);
-  uint substr_length= password_length;
-  uint substr_pos= 0;
+
   while (substr_length >= MIN_DICTIONARY_WORD_LENGTH)
   {
     substr_pos= 0;
-    while (substr_pos + substr_length <= password_length)
+    while (substr_pos + substr_length <= password->length())
     {
       password_substr= password_str.substr(substr_pos, substr_length);
-      std::transform(password_substr.begin(), password_substr.end(),
-                password_substr.begin(), (int(*)(int)) std::toupper);
       itr= dictionary_words.find(password_substr);
       if (itr != dictionary_words.end())
         return 0;
       substr_pos++;
-    }
-    substr_length--;
-  }
+     }
+     substr_length--;
+   }
   return 1;
 }
 
-static bool validate_password_policy(const char *password, uint policy)
+static bool validate_password_policy(String *password, uint policy)
 {
   uint has_numbers= 0;
   uint has_special_chars= 0;
   uint has_lower= 0;
   uint has_upper= 0;
-  uint password_length= strlen(password);
-  const char *c= password;
-  if (password_length >= validate_password_length)
+  char *beg= (char*) password->ptr();
+  char *end= (char*) password->ptr() + password->length();
+  const CHARSET_INFO *cs= password->charset();
+  if (password->length() >= validate_password_length)
   {
     if (policy == PASSWORD_STRENGTH_LOW)
       return 1;
-    while (*c != '\0')
+    while (beg < end)
     {
-      if (my_isdigit(&my_charset_latin1, *c))
+      int ctype, char_len;
+      char_len= cs->cset->ctype(cs, &ctype, (uchar*) beg, (uchar*) end);
+      if (ctype & _MY_NMR)
         has_numbers++;
-      else if (my_isupper(&my_charset_latin1, *c))
+      else if (ctype & _MY_U)
         has_upper++;
-      else if (my_islower(&my_charset_latin1, *c))
+      else if (ctype & _MY_L)
         has_lower++;
       else
         has_special_chars++;
-      c++;
+      beg+= (char_len > 0 ? char_len : (char_len < 0 ? -char_len : 1));
     }
 
-    if (has_upper >= validate_password_mixed_case_count && has_lower >=
-                     validate_password_mixed_case_count && has_special_chars >=
-                     validate_password_special_char_count && has_numbers >=
-                     validate_password_number_count)
+    if (has_upper >= validate_password_mixed_case_count &&
+        has_lower >= validate_password_mixed_case_count &&
+        has_special_chars >= validate_password_special_char_count &&
+        has_numbers >= validate_password_number_count)
     {
-      if (policy == PASSWORD_STRENGTH_MEDIUM ||
+      if (policy == PASSWORD_STRENGTH_MEDIUM || dictionary_words.empty() ||
                     validate_dictionary_check(password))
         return 1;
     }
@@ -104,12 +123,12 @@ static bool validate_password_policy(con
   return 0;
 }
 
-static bool validate_password(const char *password)
+static bool validate_password(String *password)
 {
   return validate_password_policy(password, validate_password_policy_number);
 }
 
-static uint validate_password_strength(const char *password)
+static uint validate_password_strength(String *password)
 {
   if (validate_password_policy(password, PASSWORD_STRENGTH_LOW))
   {
@@ -117,7 +136,7 @@ static uint validate_password_strength(c
     if (validate_password_policy(password, PASSWORD_STRENGTH_MEDIUM))
     {
       policy= PASSWORD_STRENGTH_MEDIUM;
-      if (validate_password_policy(password, PASSWORD_STRENGTH_STRONG))
+      if (dictionary_words.empty() || validate_dictionary_check(password))
         policy= PASSWORD_STRENGTH_STRONG;
     }
     return policy;
@@ -141,29 +160,31 @@ static int validate_password_init(void *
   char *dictionary_file;
   char default_dictionary_file[FN_REFLEN];
   string_type words;
-  long file_length;
-  fn_format(default_dictionary_file, "dictionary.txt", opt_plugin_dir,
+  ulonglong file_length;
+  fn_format(default_dictionary_file, "dictionary.txt", opt_plugin_dir_ptr,
             "", MYF(0));
   dictionary_file= (validate_password_dictionary_file ?
                     validate_password_dictionary_file :
                     default_dictionary_file);
-
   std::ifstream dictionary_stream(dictionary_file);
   if (!dictionary_stream)
-    return 1;
+  {
+    if (validate_password_dictionary_file)
+      sql_print_warning("dictionary file not found");
+    return 0;
+  }
   dictionary_stream.seekg (0, std::ios::end);
-  file_length = dictionary_stream.tellg();
+  file_length= dictionary_stream.tellg();
   dictionary_stream.seekg (0, std::ios::beg);
   if (file_length > MAX_DICTIONARY_FILE_LENGTH)
   {
     dictionary_stream.close();
-    return 1;
+    sql_print_warning("dictionary file size too large");
+    return 0;
   }
   while (dictionary_stream.good())
   {
     std::getline(dictionary_stream, words);
-    std::transform(words.begin(), words.end(), words.begin(),
-                   (int(*)(int)) std::toupper);
     dictionary_words.insert(words);
   }
   dictionary_stream.close();
@@ -183,7 +204,7 @@ static int validate_password_deinit(void
 
 static MYSQL_SYSVAR_UINT(length, validate_password_length,
   PLUGIN_VAR_RQCMDARG,
-  "Password_validate_length to check for minimum password_length",
+  "Password validate length to check for minimum password_length",
   NULL, NULL, 8, 0, 0, 0);
 
 static MYSQL_SYSVAR_UINT(number_count, validate_password_number_count,

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2012-04-16 12:25:21 +0000
+++ b/sql/item_func.cc	2012-04-30 06:36:01 +0000
@@ -3233,8 +3233,7 @@ longlong Item_func_validate_password_str
   String *field;
   if (!(field= args[0]->val_str(&value)))
     return 0;
-  const char * password= field->ptr();
-    return (check_password_strength(password));
+    return (check_password_strength(field));
 }
 
 

=== modified file 'sql/item_strfunc.cc'
--- a/sql/item_strfunc.cc	2012-04-23 15:41:09 +0000
+++ b/sql/item_strfunc.cc	2012-04-30 06:36:01 +0000
@@ -1925,7 +1925,7 @@ String *Item_func_password::val_str_asci
   String *res= args[0]->val_str(str); 
   if ((null_value=args[0]->null_value))
     return 0;
-  check_password_policy(res->ptr());
+  check_password_policy(res);
   if (res->length() == 0)
     return make_empty_result();
   my_make_scrambled_password(tmp_value, res->ptr(), res->length());

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2012-04-23 15:41:09 +0000
+++ b/sql/sql_acl.cc	2012-04-30 06:36:01 +0000
@@ -9917,7 +9917,7 @@ mysql_declare_plugin_end;
 
 /* for validate_password_strength SQL function */
 
-int check_password_strength(const char *password)
+int check_password_strength(String *password)
 {
   int res= 0;
   plugin_ref plugin= my_plugin_lock_by_name(0, &validate_password_plugin_name,
@@ -9927,8 +9927,7 @@ int check_password_strength(const char *
     st_mysql_validate_password *password_strength=
                       (st_mysql_validate_password *) plugin_decl(plugin)->info;
 
-    if (!(res= password_strength->validate_password_strength(password)))
-      my_error(ER_NOT_VALID_PASSWORD, MYF(0), password);
+    res= password_strength->validate_password_strength(password);
     plugin_unlock(0, plugin);
   }
   return(res);
@@ -9936,7 +9935,7 @@ int check_password_strength(const char *
 
 /* called when new user is created or exsisting password is changed */
 
-void check_password_policy(const char *password)
+void check_password_policy(String *password)
 {
   plugin_ref plugin= my_plugin_lock_by_name(0, &validate_password_plugin_name,
                                             MYSQL_VALIDATE_PASSWORD_PLUGIN);
@@ -9946,7 +9945,7 @@ void check_password_policy(const char *p
                       (st_mysql_validate_password *) plugin_decl(plugin)->info;
 
     if (!password_validate->validate_password(password))
-      my_error(ER_NOT_VALID_PASSWORD, MYF(0), password);
+      my_error(ER_NOT_VALID_PASSWORD, MYF(0), password->ptr());
     plugin_unlock(0, plugin);
   }
 }

=== modified file 'sql/sql_acl.h'
--- a/sql/sql_acl.h	2012-04-23 15:41:09 +0000
+++ b/sql/sql_acl.h	2012-04-30 06:36:01 +0000
@@ -251,8 +251,8 @@ int fill_schema_schema_privileges(THD *t
 int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, Item *cond);
 int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, Item *cond);
 int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
-int check_password_strength(const char *password);
-void check_password_policy(const char *password);
+int check_password_strength(String *password);
+void check_password_policy(String *password);
 
 #ifdef NO_EMBEDDED_ACCESS_CHECKS
 #define check_grant(A,B,C,D,E,F) 0

=== modified file 'sql/sql_plugin.h'
--- a/sql/sql_plugin.h	2012-04-24 15:36:30 +0000
+++ b/sql/sql_plugin.h	2012-04-30 06:36:01 +0000
@@ -135,8 +135,8 @@ typedef struct st_plugin_int **plugin_re
 typedef int (*plugin_type_init)(struct st_plugin_int *);
 
 extern I_List<i_string> *opt_plugin_load_list_ptr;
-extern char *opt_plugin_dir_ptr;
-extern MYSQL_PLUGIN_IMPORT char opt_plugin_dir[FN_REFLEN];
+extern MYSQL_PLUGIN_IMPORT char *opt_plugin_dir_ptr;
+extern char opt_plugin_dir[FN_REFLEN];
 extern const LEX_STRING plugin_type_names[];
 extern int plugin_init(int *argc, char **argv, int init_flags);
 extern void plugin_shutdown(void);

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2012-04-23 15:41:09 +0000
+++ b/sql/sql_yacc.yy	2012-04-30 06:36:01 +0000
@@ -14199,7 +14199,9 @@ text_or_password:
           TEXT_STRING { $$=$1.str;}
         | PASSWORD '(' TEXT_STRING ')'
           {
-            check_password_policy($3.str);
+            String *password = new (YYTHD->mem_root) String((const char*)$3.str,
+                                    YYTHD->variables.character_set_client);
+            check_password_policy(password);
             $$= $3.length ? YYTHD->variables.old_passwords ?
               Item_func_old_password::alloc(YYTHD, $3.str, $3.length) :
               Item_func_password::alloc(YYTHD, $3.str, $3.length) :
@@ -14708,7 +14710,9 @@ grant_user:
             $$=$1; $1->password=$4;
             if (Lex->sql_command == SQLCOM_REVOKE)
               MYSQL_YYABORT;
-            check_password_policy($4.str);
+            String *password = new (YYTHD->mem_root) String((const char*)$4.str,
+                                    YYTHD->variables.character_set_client);
+            check_password_policy(password);
             if ($4.length)
             {
               if (YYTHD->variables.old_passwords)

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (ashish.y.agarwal:3879 to 3880) Ashish Agarwal30 Apr