| 1 | /* Copyright (c) 2014, Sergei Golubchik and MariaDB |
| 2 | Copyright (c) 2012, 2013, Oracle and/or its affiliates. |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by |
| 6 | the Free Software Foundation; version 2 of the License. |
| 7 | |
| 8 | This program is distributed in the hope that it will be useful, |
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | GNU General Public License for more details. |
| 12 | |
| 13 | You should have received a copy of the GNU General Public License |
| 14 | along with this program; if not, write to the Free Software |
| 15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 16 | |
| 17 | #include <mysqld_error.h> |
| 18 | #include <my_attribute.h> |
| 19 | #include <mysql/plugin_password_validation.h> |
| 20 | #include <ctype.h> |
| 21 | #include <string.h> |
| 22 | |
| 23 | static unsigned min_length, min_digits, min_letters, min_others; |
| 24 | |
| 25 | static int validate(MYSQL_CONST_LEX_STRING *username, |
| 26 | MYSQL_CONST_LEX_STRING *password) |
| 27 | { |
| 28 | unsigned digits=0 , uppers=0 , lowers=0, others=0, length= (unsigned)password->length; |
| 29 | const char *ptr= password->str, *end= ptr + length; |
| 30 | |
| 31 | if (strncmp(password->str, username->str, length) == 0) |
| 32 | return 1; |
| 33 | |
| 34 | /* everything non-ascii is the "other" character and is good for the password */ |
| 35 | for(; ptr < end; ptr++) |
| 36 | { |
| 37 | if (isdigit(*ptr)) |
| 38 | digits++; |
| 39 | else if (isupper(*ptr)) |
| 40 | uppers++; |
| 41 | else if (islower(*ptr)) |
| 42 | lowers++; |
| 43 | else |
| 44 | others++; |
| 45 | } |
| 46 | /* remember TRUE means the password failed the validation */ |
| 47 | return length < min_length || |
| 48 | uppers < min_letters || |
| 49 | lowers < min_letters || |
| 50 | digits < min_digits || |
| 51 | others < min_others; |
| 52 | } |
| 53 | |
| 54 | static void fix_min_length(MYSQL_THD thd __attribute__((unused)), |
| 55 | struct st_mysql_sys_var *var |
| 56 | __attribute__((unused)), |
| 57 | void *var_ptr, const void *save) |
| 58 | { |
| 59 | unsigned int new_min_length; |
| 60 | *((unsigned int *)var_ptr)= *((unsigned int *)save); |
| 61 | new_min_length= min_digits + 2 * min_letters + min_others; |
| 62 | if (min_length < new_min_length) |
| 63 | { |
| 64 | my_printf_error(ER_TRUNCATED_WRONG_VALUE, |
| 65 | "Adjusted the value of simple_password_check_minimal_length " |
| 66 | "from %u to %u" , ME_WARNING, min_length, new_min_length); |
| 67 | min_length= new_min_length; |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | |
| 72 | static MYSQL_SYSVAR_UINT(minimal_length, min_length, PLUGIN_VAR_RQCMDARG, |
| 73 | "Minimal required password length" , NULL, fix_min_length, 8, 0, 1000, 1); |
| 74 | |
| 75 | static MYSQL_SYSVAR_UINT(digits, min_digits, PLUGIN_VAR_RQCMDARG, |
| 76 | "Minimal required number of digits" , NULL, fix_min_length, 1, 0, 1000, 1); |
| 77 | |
| 78 | static MYSQL_SYSVAR_UINT(letters_same_case, min_letters, PLUGIN_VAR_RQCMDARG, |
| 79 | "Minimal required number of letters of the same letter case." |
| 80 | "This limit is applied separately to upper-case and lower-case letters" , |
| 81 | NULL, fix_min_length, 1, 0, 1000, 1); |
| 82 | |
| 83 | static MYSQL_SYSVAR_UINT(other_characters, min_others, PLUGIN_VAR_RQCMDARG, |
| 84 | "Minimal required number of other (not letters or digits) characters" , |
| 85 | NULL, fix_min_length, 1, 0, 1000, 1); |
| 86 | |
| 87 | static struct st_mysql_sys_var* sysvars[]= { |
| 88 | MYSQL_SYSVAR(minimal_length), |
| 89 | MYSQL_SYSVAR(digits), |
| 90 | MYSQL_SYSVAR(letters_same_case), |
| 91 | MYSQL_SYSVAR(other_characters), |
| 92 | NULL |
| 93 | }; |
| 94 | |
| 95 | static struct st_mariadb_password_validation info= |
| 96 | { |
| 97 | MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION, |
| 98 | validate |
| 99 | }; |
| 100 | |
| 101 | maria_declare_plugin(simple_password_check) |
| 102 | { |
| 103 | MariaDB_PASSWORD_VALIDATION_PLUGIN, |
| 104 | &info, |
| 105 | "simple_password_check" , |
| 106 | "Sergei Golubchik" , |
| 107 | "Simple password strength checks" , |
| 108 | PLUGIN_LICENSE_GPL, |
| 109 | NULL, |
| 110 | NULL, |
| 111 | 0x0100, |
| 112 | NULL, |
| 113 | sysvars, |
| 114 | "1.0" , |
| 115 | MariaDB_PLUGIN_MATURITY_STABLE |
| 116 | } |
| 117 | maria_declare_plugin_end; |
| 118 | |