diff options
-rw-r--r-- | include/crypt_genhash_impl.h | 32 | ||||
-rw-r--r-- | include/mysql/client_authentication.h | 13 | ||||
-rw-r--r-- | include/mysql_com.h | 4 | ||||
-rw-r--r-- | include/password.h | 2 | ||||
-rw-r--r-- | include/sql_common.h | 1 | ||||
-rw-r--r-- | libmysql/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libmysql/client_settings.h | 1 | ||||
-rw-r--r-- | mysys_ssl/CMakeLists.txt | 2 | ||||
-rw-r--r-- | mysys_ssl/crypt_genhash_impl.cc | 454 | ||||
-rw-r--r-- | sql-common/client.c | 41 | ||||
-rw-r--r-- | sql-common/client_authentication.cc | 253 | ||||
-rw-r--r-- | sql-common/pack.c | 96 | ||||
-rw-r--r-- | sql/client_settings.h | 1 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 121 | ||||
-rw-r--r-- | sql/item_strfunc.h | 17 | ||||
-rw-r--r-- | sql/password.c | 55 | ||||
-rw-r--r-- | sql/sql_acl.cc | 15 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 20 |
18 files changed, 170 insertions, 959 deletions
diff --git a/include/crypt_genhash_impl.h b/include/crypt_genhash_impl.h deleted file mode 100644 index af5afd23e86..00000000000 --- a/include/crypt_genhash_impl.h +++ /dev/null @@ -1,32 +0,0 @@ -/* defines and prototypes for using crypt_genhash_impl.cc */ - -#ifndef CRYPT_HASHGEN_IMPL_H -#define CRYPT_HASHGEN_IMPL_H -#define ROUNDS_DEFAULT 5000 -#define ROUNDS_MIN 1000 -#define ROUNDS_MAX 999999999 -#define MIXCHARS 32 -#define CRYPT_SALT_LENGTH 20 -#define CRYPT_MAGIC_LENGTH 3 -#define CRYPT_PARAM_LENGTH 13 -#define SHA256_HASH_LENGTH 43 -#define CRYPT_MAX_PASSWORD_SIZE (CRYPT_SALT_LENGTH + \ - SHA256_HASH_LENGTH + \ - CRYPT_MAGIC_LENGTH + \ - CRYPT_PARAM_LENGTH) - -int extract_user_salt(char **salt_begin, - char **salt_end); -C_MODE_START -char * -my_crypt_genhash(char *ctbuffer, - size_t ctbufflen, - const char *plaintext, - int plaintext_len, - const char *switchsalt, - const char **params); -void generate_user_salt(char *buffer, int buffer_len); -void xor_string(char *to, int to_len, char *pattern, int pattern_len); - -C_MODE_END -#endif diff --git a/include/mysql/client_authentication.h b/include/mysql/client_authentication.h deleted file mode 100644 index 2bd2fc98bac..00000000000 --- a/include/mysql/client_authentication.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CLIENT_AUTHENTICATION_H -#define CLIENT_AUTHENTICATION_H -#include "mysql.h" -#include "mysql/client_plugin.h" - -C_MODE_START -int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); -int sha256_password_init(char *, size_t, int, va_list); -int sha256_password_deinit(void); -C_MODE_END - -#endif - diff --git a/include/mysql_com.h b/include/mysql_com.h index d9f905eb657..be1d222eb07 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -265,11 +265,11 @@ enum enum_server_command CLIENT_REMEMBER_OPTIONS | \ CLIENT_PROGRESS | \ CLIENT_PLUGIN_AUTH | \ + CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ CLIENT_CONNECT_ATTRS) /* To be added later: - CLIENT_CONNECT_ATTRS, CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA, CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS */ @@ -641,7 +641,9 @@ void my_thread_end(void); #ifdef MY_GLOBAL_INCLUDED ulong STDCALL net_field_length(uchar **packet); my_ulonglong net_field_length_ll(uchar **packet); +my_ulonglong safe_net_field_length_ll(uchar **packet, size_t packet_len); uchar *net_store_length(uchar *pkg, ulonglong length); +uchar *safe_net_store_length(uchar *pkg, size_t pkg_len, ulonglong length); #endif #ifdef __cplusplus diff --git a/include/password.h b/include/password.h index 5dfea533546..082f917e7c0 100644 --- a/include/password.h +++ b/include/password.h @@ -24,8 +24,6 @@ void my_make_scrambled_password_323(char *to, const char *password, size_t pass_len); void my_make_scrambled_password(char *to, const char *password, size_t pass_len); -void my_make_scrambled_password_sha1(char *to, const char *password, - size_t pass_len); void hash_password(ulong *result, const char *password, uint password_len); diff --git a/include/sql_common.h b/include/sql_common.h index e7bade7e73b..39b8ce18517 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -35,7 +35,6 @@ struct st_mysql_options_extention { char *default_auth; char *ssl_crl; /* PEM CRL file */ char *ssl_crlpath; /* PEM directory of CRL-s? */ - char *server_public_key_path; void (*report_progress)(const MYSQL *mysql, unsigned int stage, unsigned int max_stage, diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index bcbb3d6cffe..43b0c6187b9 100644 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -337,7 +337,6 @@ SET(CLIENT_SOURCES ../sql-common/mysql_async.c ../sql-common/my_time.c ../sql-common/client_plugin.c - ../sql-common/client_authentication.cc ../sql/net_serv.cc ../sql-common/pack.c ../sql/password.c diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h index 4fbec521238..b233614fa1e 100644 --- a/libmysql/client_settings.h +++ b/libmysql/client_settings.h @@ -35,6 +35,7 @@ extern char * mysql_unix_port; CLIENT_MULTI_RESULTS | \ CLIENT_PS_MULTI_RESULTS | \ CLIENT_PLUGIN_AUTH | \ + CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ CLIENT_CONNECT_ATTRS) sig_handler my_pipe_sig_handler(int sig); diff --git a/mysys_ssl/CMakeLists.txt b/mysys_ssl/CMakeLists.txt index b91988d1c8b..45867095e4a 100644 --- a/mysys_ssl/CMakeLists.txt +++ b/mysys_ssl/CMakeLists.txt @@ -26,7 +26,6 @@ ENDIF() # must be compiled with "-fvisibility=hidden" IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) SET_SOURCE_FILES_PROPERTIES( - crypt_genhash_impl.cc my_aes.cc my_md5.cc my_sha1.cc @@ -35,7 +34,6 @@ IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN) ENDIF() SET(MYSYS_SSL_SOURCES - crypt_genhash_impl.cc my_aes.cc my_sha1.cc my_sha2.cc diff --git a/mysys_ssl/crypt_genhash_impl.cc b/mysys_ssl/crypt_genhash_impl.cc deleted file mode 100644 index ab7fdec46b9..00000000000 --- a/mysys_ssl/crypt_genhash_impl.cc +++ /dev/null @@ -1,454 +0,0 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. 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; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */ - -/* We always should include my_global first */ - -#include <my_global.h> - -#ifdef HAVE_OPENSSL - -#ifdef HAVE_YASSL -#include <sha.hpp> -#include <openssl/ssl.h> -#else -#include <openssl/sha.h> -#include <openssl/rand.h> -#endif -#include "crypt_genhash_impl.h" -#include <string.h> - -#ifndef HAVE_YASSL -#define DIGEST_CTX SHA256_CTX -#define DIGESTInit SHA256_Init -#define DIGESTUpdate SHA256_Update -#define DIGESTFinal SHA256_Final -#define DIGEST_LEN SHA256_DIGEST_LENGTH -#else -#define DIGEST_CTX TaoCrypt::SHA256 -#define DIGEST_LEN 32 -void DIGESTInit(DIGEST_CTX *ctx) -{ - ctx->Init(); -} - -void DIGESTUpdate(DIGEST_CTX *ctx, const void *plaintext, int len) -{ - ctx->Update((const TaoCrypt::byte *)plaintext, len); -} - -void DIGESTFinal(void *txt, DIGEST_CTX *ctx) -{ - ctx->Final((TaoCrypt::byte *)txt); -} - -#endif // HAVE_YASSL - -static const char crypt_alg_magic[] = "$5"; - -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - - -/** - Size-bounded string copying and concatenation - This is a replacement for STRLCPY(3) -*/ - -size_t -strlcat(char *dst, const char *src, size_t siz) -{ - char *d= dst; - const char *s= src; - size_t n= siz; - size_t dlen; - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen= d - dst; - n= siz - dlen; - if (n == 0) - return(dlen + siz); - while (*s != '\0') - { - if (n != 1) - { - *d++= *s; - n--; - } - s++; - } - *d= '\0'; - return(dlen + (s - src)); /* count does not include NUL */ -} - -static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1; - -static unsigned char b64t[] = /* 0 ... 63 => ascii - 64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -#define b64_from_24bit(B2, B1, B0, N) \ -{ \ - uint32 w = ((B2) << 16) | ((B1) << 8) | (B0); \ - int n = (N); \ - while (--n >= 0 && ctbufflen > 0) { \ - *p++ = b64t[w & 0x3f]; \ - w >>= 6; \ - ctbufflen--; \ -} \ -} - -#define ROUNDS "rounds=" -#define ROUNDSLEN (sizeof (ROUNDS) - 1) - -/** - Get the integer value after rounds= where ever it occurs in the string. - if the last char after the int is a , or $ that is fine anything else is an - error. -*/ -static uint32 getrounds(const char *s) -{ - const char *r; - const char *p; - char *e; - long val; - - if (s == NULL) - return (0); - - if ((r = strstr(s, ROUNDS)) == NULL) - { - return (0); - } - - if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) - { - return (0); - } - - p= r + ROUNDSLEN; - errno= 0; - val= strtol(p, &e, 10); - /* - An error occurred or there is non-numeric stuff at the end - which isn't one of the crypt(3c) special chars ',' or '$' - */ - if (errno != 0 || val < 0 || !(*e == '\0' || *e == ',' || *e == '$')) - { - return (0); - } - - return ((uint32) val); -} - -/** - Finds the interval which envelopes the user salt in a crypt password - The crypt format is assumed to be $a$bbbb$cccccc\0 and the salt is found - by counting the delimiters and marking begin and end. - - @param salt_being[in] Pointer to start of crypt passwd - @param salt_being[out] Pointer to first byte of the salt - @param salt_end[in] Pointer to the last byte in passwd - @param salt_end[out] Pointer to the byte immediatly following the salt ($) - - @return The size of the salt identified -*/ - -int extract_user_salt(char **salt_begin, - char **salt_end) -{ - char *it= *salt_begin; - int delimiter_count= 0; - while(it != *salt_end) - { - if (*it == '$') - { - ++delimiter_count; - if (delimiter_count == 2) - { - *salt_begin= it + 1; - } - if (delimiter_count == 3) - break; - } - ++it; - } - *salt_end= it; - return *salt_end - *salt_begin; -} - -const char *sha256_find_digest(char *pass) -{ - int sz= strlen(pass); - return pass + sz - SHA256_HASH_LENGTH; -} - -/* - * Portions of the below code come from crypt_bsdmd5.so (bsdmd5.c) : - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - * - * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ - * - */ - -/* - * The below code implements the specification from: - * - * From http://people.redhat.com/drepper/SHA-crypt.txt - * - * Portions of the code taken from inspired by or verified against the - * source in the above document which is licensed as: - * - * "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>." - */ - -/* - Due to a Solaris namespace bug DS is a reserved word. To work around this - DS is undefined. -*/ -#undef DS - -/* ARGSUSED4 */ -extern "C" -char * -my_crypt_genhash(char *ctbuffer, - size_t ctbufflen, - const char *plaintext, - int plaintext_len, - const char *switchsalt, - const char **params) -{ - int salt_len, i; - char *salt; - unsigned char A[DIGEST_LEN]; - unsigned char B[DIGEST_LEN]; - unsigned char DP[DIGEST_LEN]; - unsigned char DS[DIGEST_LEN]; - DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS; - int rounds = ROUNDS_DEFAULT; - int srounds = 0; - bool custom_rounds= false; - char *p; - char *P, *Pp; - char *S, *Sp; - - /* Refine the salt */ - salt = (char *)switchsalt; - - /* skip our magic string */ - if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0) - { - salt += crypt_alg_magic_len + 1; - } - - srounds = getrounds(salt); - if (srounds != 0) { - rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX)); - custom_rounds= true; - p = strchr(salt, '$'); - if (p != NULL) - salt = p + 1; - } - - salt_len = MIN(strcspn(salt, "$"), CRYPT_SALT_LENGTH); - //plaintext_len = strlen(plaintext); - - /* 1. */ - DIGESTInit(&ctxA); - - /* 2. The password first, since that is what is most unknown */ - DIGESTUpdate(&ctxA, plaintext, plaintext_len); - - /* 3. Then the raw salt */ - DIGESTUpdate(&ctxA, salt, salt_len); - - /* 4. - 8. */ - DIGESTInit(&ctxB); - DIGESTUpdate(&ctxB, plaintext, plaintext_len); - DIGESTUpdate(&ctxB, salt, salt_len); - DIGESTUpdate(&ctxB, plaintext, plaintext_len); - DIGESTFinal(B, &ctxB); - - /* 9. - 10. */ - for (i= plaintext_len; i > MIXCHARS; i -= MIXCHARS) - DIGESTUpdate(&ctxA, B, MIXCHARS); - DIGESTUpdate(&ctxA, B, i); - - /* 11. */ - for (i= plaintext_len; i > 0; i >>= 1) { - if ((i & 1) != 0) - { - DIGESTUpdate(&ctxA, B, MIXCHARS); - } - else - { - DIGESTUpdate(&ctxA, plaintext, plaintext_len); - } - } - - /* 12. */ - DIGESTFinal(A, &ctxA); - - /* 13. - 15. */ - DIGESTInit(&ctxDP); - for (i= 0; i < plaintext_len; i++) - DIGESTUpdate(&ctxDP, plaintext, plaintext_len); - DIGESTFinal(DP, &ctxDP); - - /* 16. */ - Pp= P= (char *)alloca(plaintext_len); - for (i= plaintext_len; i >= MIXCHARS; i -= MIXCHARS) - { - Pp= (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS; - } - (void) memcpy(Pp, DP, i); - - /* 17. - 19. */ - DIGESTInit(&ctxDS); - for (i= 0; i < 16 + (uint8)A[0]; i++) - DIGESTUpdate(&ctxDS, salt, salt_len); - DIGESTFinal(DS, &ctxDS); - - /* 20. */ - Sp= S= (char *)alloca(salt_len); - for (i= salt_len; i >= MIXCHARS; i -= MIXCHARS) - { - Sp= (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS; - } - (void) memcpy(Sp, DS, i); - - /* 21. */ - for (i= 0; i < rounds; i++) - { - DIGESTInit(&ctxC); - - if ((i & 1) != 0) - { - DIGESTUpdate(&ctxC, P, plaintext_len); - } - else - { - if (i == 0) - DIGESTUpdate(&ctxC, A, MIXCHARS); - else - DIGESTUpdate(&ctxC, DP, MIXCHARS); - } - - if (i % 3 != 0) { - DIGESTUpdate(&ctxC, S, salt_len); - } - - if (i % 7 != 0) { - DIGESTUpdate(&ctxC, P, plaintext_len); - } - - if ((i & 1) != 0) - { - if (i == 0) - DIGESTUpdate(&ctxC, A, MIXCHARS); - else - DIGESTUpdate(&ctxC, DP, MIXCHARS); - } - else - { - DIGESTUpdate(&ctxC, P, plaintext_len); - } - DIGESTFinal(DP, &ctxC); - } - - /* 22. Now make the output string */ - if (custom_rounds) - { - (void) snprintf(ctbuffer, ctbufflen, - "%s$rounds=%zu$", crypt_alg_magic, (size_t)rounds); - } - else - { - (void) snprintf(ctbuffer, ctbufflen, - "%s$", crypt_alg_magic); - } - (void) strncat(ctbuffer, (const char *)salt, salt_len); - (void) strlcat(ctbuffer, "$", ctbufflen); - - p= ctbuffer + strlen(ctbuffer); - ctbufflen -= strlen(ctbuffer); - - b64_from_24bit(DP[ 0], DP[10], DP[20], 4); - b64_from_24bit(DP[21], DP[ 1], DP[11], 4); - b64_from_24bit(DP[12], DP[22], DP[ 2], 4); - b64_from_24bit(DP[ 3], DP[13], DP[23], 4); - b64_from_24bit(DP[24], DP[ 4], DP[14], 4); - b64_from_24bit(DP[15], DP[25], DP[ 5], 4); - b64_from_24bit(DP[ 6], DP[16], DP[26], 4); - b64_from_24bit(DP[27], DP[ 7], DP[17], 4); - b64_from_24bit(DP[18], DP[28], DP[ 8], 4); - b64_from_24bit(DP[ 9], DP[19], DP[29], 4); - b64_from_24bit(0, DP[31], DP[30], 3); - *p= '\0'; - - (void) memset(A, 0, sizeof (A)); - (void) memset(B, 0, sizeof (B)); - (void) memset(DP, 0, sizeof (DP)); - (void) memset(DS, 0, sizeof (DS)); - - return (ctbuffer); -} - - -/** - Generate a random string using ASCII characters but avoid seperator character. - Stdlib rand and srand are used to produce pseudo random numbers between - with about 7 bit worth of entropty between 1-127. -*/ -extern "C" -void generate_user_salt(char *buffer, int buffer_len) -{ - char *end= buffer + buffer_len - 1; -#ifdef HAVE_YASSL - yaSSL::RAND_bytes((unsigned char *) buffer, buffer_len); -#else - RAND_bytes((unsigned char *) buffer, buffer_len); -#endif - - /* Sequence must be a legal UTF8 string */ - for (; buffer < end; buffer++) - { - *buffer &= 0x7f; - if (*buffer == '\0' || *buffer == '$') - *buffer= *buffer + 1; - } - /* Make sure the buffer is terminated properly */ - *end= '\0'; -} - -void xor_string(char *to, int to_len, char *pattern, int pattern_len) -{ - int loop= 0; - while(loop <= to_len) - { - *(to + loop) ^= *(pattern + loop % pattern_len); - ++loop; - } -} - -#endif // HAVE_OPENSSL diff --git a/sql-common/client.c b/sql-common/client.c index 87cbf45a3c6..fa2d9acfd03 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2477,6 +2477,29 @@ typedef struct { int last_read_packet_len; /**< the length of the last *read* packet */ } MCPVIO_EXT; + +/* + Write 1-8 bytes of string length header infromation to dest depending on + value of src_len, then copy src_len bytes from src to dest. + + @param dest Destination buffer of size src_len+8 + @param dest_end One byte past the end of the dest buffer + @param src Source buff of size src_len + @param src_end One byte past the end of the src buffer + + @return pointer dest+src_len+header size or NULL if +*/ + +static uchar *write_length_encoded_string4(uchar *dst, size_t dst_len, + const uchar *src, size_t src_len) +{ + uchar *to= safe_net_store_length(dst, dst_len, src_len); + if (to == NULL) + return NULL; + memcpy(to, src, src_len); + return to + src_len; +} + /** sends a COM_CHANGE_USER command with a caller provided payload @@ -2578,7 +2601,7 @@ error: 1 charset number 23 reserved (always 0) n user name, \0-terminated - n plugin auth data (e.g. scramble), length (1 byte) coded + n plugin auth data (e.g. scramble), length encoded n database name, \0-terminated (if CLIENT_CONNECT_WITH_DB is set in the capabilities) n client auth plugin name - \0-terminated string, @@ -2736,9 +2759,19 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, { if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) { - *end++= data_len; - memcpy(end, data, data_len); - end+= data_len; + if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) + end= (char*)write_length_encoded_string4((uchar*)end, + buff_size, data, data_len); + else + { + if (data_len > 255) + goto error; + *end++= data_len; + memcpy(end, data, data_len); + end+= data_len; + } + if (end == NULL) + goto error; } else { diff --git a/sql-common/client_authentication.cc b/sql-common/client_authentication.cc deleted file mode 100644 index 195f37bcc59..00000000000 --- a/sql-common/client_authentication.cc +++ /dev/null @@ -1,253 +0,0 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. - Copyright (c) 2013, Monty Program Ab - - 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; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */ - -#include <my_global.h> - -#if defined(HAVE_OPENSSL) -#include "crypt_genhash_impl.h" -#include "mysql/client_authentication.h" -#include "m_ctype.h" -#include "sql_common.h" -#include "errmsg.h" -#include "m_string.h" -#include <string.h> - -#if !defined(HAVE_YASSL) -#include <openssl/rsa.h> -#include <openssl/pem.h> -#include <openssl/err.h> -#if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C) -#include <openssl/applink.c> -#endif -#endif -#include "mysql/service_my_plugin_log.h" - -#define MAX_CIPHER_LENGTH 1024 - -#if !defined(HAVE_YASSL) -mysql_mutex_t g_public_key_mutex; -#endif - -int sha256_password_init(char *a, size_t b, int c, va_list d) -{ -#if !defined(HAVE_YASSL) - mysql_mutex_init(0,&g_public_key_mutex, MY_MUTEX_INIT_SLOW); -#endif - return 0; -} - -int sha256_password_deinit(void) -{ -#if !defined(HAVE_YASSL) - mysql_mutex_destroy(&g_public_key_mutex); -#endif - return 0; -} - - -#if !defined(HAVE_YASSL) -/** - Reads and parse RSA public key data from a file. - - @param mysql connection handle with file path data - - @return Pointer to the RSA public key storage buffer -*/ - -RSA *rsa_init(MYSQL *mysql) -{ - static RSA *g_public_key= NULL; - RSA *key= NULL; - - mysql_mutex_lock(&g_public_key_mutex); - key= g_public_key; - mysql_mutex_unlock(&g_public_key_mutex); - - if (key != NULL) - return key; - - FILE *pub_key_file= NULL; - - if (mysql->options.extension != NULL && - mysql->options.extension->server_public_key_path != NULL && - mysql->options.extension->server_public_key_path != '\0') - { - pub_key_file= fopen(mysql->options.extension->server_public_key_path, - "r"); - } - /* No public key is used; return 0 without errors to indicate this. */ - else - return 0; - - if (pub_key_file == NULL) - { - /* - If a key path was submitted but no key located then we print an error - message. Else we just report that there is no public key. - */ - fprintf(stderr,"Can't locate server public key '%s'\n", - mysql->options.extension->server_public_key_path); - - return 0; - } - - mysql_mutex_lock(&g_public_key_mutex); - key= g_public_key= PEM_read_RSA_PUBKEY(pub_key_file, 0, 0, 0); - mysql_mutex_unlock(&g_public_key_mutex); - fclose(pub_key_file); - if (g_public_key == NULL) - { - fprintf(stderr, "Public key is not in PEM format: '%s'\n", - mysql->options.extension->server_public_key_path); - return 0; - } - - return key; -} -#endif // !defined(HAVE_YASSL) - -/** - Authenticate the client using the RSA or TLS and a SHA256 salted password. - - @param vio Provides plugin access to communication channel - @param mysql Client connection handler - - @return Error status - @retval CR_ERROR An error occurred. - @retval CR_OK Authentication succeeded. -*/ - -extern "C" -int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) -{ - bool uses_password= mysql->passwd[0] != 0; -#if !defined(HAVE_YASSL) - unsigned char encrypted_password[MAX_CIPHER_LENGTH]; - static char request_public_key= '\1'; - RSA *public_key= NULL; - bool got_public_key_from_server= false; -#endif - bool connection_is_secure= false; - unsigned char scramble_pkt[20]; - unsigned char *pkt; - - - DBUG_ENTER("sha256_password_auth_client"); - - /* - Get the scramble from the server because we need it when sending encrypted - password. - */ - if (vio->read_packet(vio, &pkt) != SCRAMBLE_LENGTH) - { - DBUG_PRINT("info",("Scramble is not of correct length.")); - DBUG_RETURN(CR_ERROR); - } - /* - Copy the scramble to the stack or it will be lost on the next use of the - net buffer. - */ - memcpy(scramble_pkt, pkt, SCRAMBLE_LENGTH); - - if (mysql_get_ssl_cipher(mysql) != NULL) - connection_is_secure= true; - - /* If connection isn't secure attempt to get the RSA public key file */ - if (!connection_is_secure) - { - #if !defined(HAVE_YASSL) - public_key= rsa_init(mysql); -#endif - } - - if (!uses_password) - { - /* We're not using a password */ - static const unsigned char zero_byte= '\0'; - if (vio->write_packet(vio, (const unsigned char *) &zero_byte, 1)) - DBUG_RETURN(CR_ERROR); - } - else - { - /* Password is a 0-terminated byte array ('\0' character included) */ - unsigned int passwd_len= strlen(mysql->passwd) + 1; - if (!connection_is_secure) - { -#if !defined(HAVE_YASSL) - /* - If no public key; request one from the server. - */ - if (public_key == NULL) - { - if (vio->write_packet(vio, (const unsigned char *) &request_public_key, - 1)) - DBUG_RETURN(CR_ERROR); - - int pkt_len= 0; - unsigned char *pkt; - if ((pkt_len= vio->read_packet(vio, &pkt)) == -1) - DBUG_RETURN(CR_ERROR); - BIO* bio= BIO_new_mem_buf(pkt, pkt_len); - public_key= PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL); - BIO_free(bio); - if (public_key == 0) - DBUG_RETURN(CR_ERROR); - got_public_key_from_server= true; - } - - /* Obfuscate the plain text password with the session scramble */ - xor_string(mysql->passwd, strlen(mysql->passwd), (char *) scramble_pkt, - SCRAMBLE_LENGTH); - /* Encrypt the password and send it to the server */ - int cipher_length= RSA_size(public_key); - /* - When using RSA_PKCS1_OAEP_PADDING the password length must be less - than RSA_size(rsa) - 41. - */ - if (passwd_len + 41 >= (unsigned) cipher_length) - { - /* password message is to long */ - DBUG_RETURN(CR_ERROR); - } - RSA_public_encrypt(passwd_len, (unsigned char *) mysql->passwd, - encrypted_password, - public_key, RSA_PKCS1_OAEP_PADDING); - if (got_public_key_from_server) - RSA_free(public_key); - - if (vio->write_packet(vio, (uchar*) encrypted_password, cipher_length)) - DBUG_RETURN(CR_ERROR); -#else - set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_ERR, unknown_sqlstate, - ER(CR_AUTH_PLUGIN_ERR), "sha256_password", - "Authentication requires SSL encryption"); - DBUG_RETURN(CR_ERROR); // If no openssl support -#endif - } - else - { - /* The vio is encrypted already; just send the plain text passwd */ - if (vio->write_packet(vio, (uchar*) mysql->passwd, passwd_len)) - DBUG_RETURN(CR_ERROR); - } - - memset(mysql->passwd, 0, passwd_len); - } - - DBUG_RETURN(CR_OK); -} - -#endif diff --git a/sql-common/pack.c b/sql-common/pack.c index 9c920279cf8..f0932e49617 100644 --- a/sql-common/pack.c +++ b/sql-common/pack.c @@ -48,7 +48,7 @@ ulong STDCALL net_field_length(uchar **packet) /* The same as above but returns longlong */ my_ulonglong net_field_length_ll(uchar **packet) { - reg1 uchar *pos= *packet; + uchar *pos= *packet; if (*pos < 251) { (*packet)++; @@ -69,12 +69,47 @@ my_ulonglong net_field_length_ll(uchar **packet) (*packet)+=4; return (my_ulonglong) uint3korr(pos+1); } + DBUG_ASSERT(*pos == 254); (*packet)+=9; /* Must be 254 when here */ -#ifdef NO_CLIENT_LONGLONG - return (my_ulonglong) uint4korr(pos+1); -#else return (my_ulonglong) uint8korr(pos+1); -#endif +} + +my_ulonglong safe_net_field_length_ll(uchar **packet, size_t packet_len) +{ + uchar *pos= *packet; + if (packet_len < 1) + goto err; + if (*pos < 251) + { + (*packet)++; + return (my_ulonglong) *pos; + } + if (*pos == 251) + { + (*packet)++; + return (my_ulonglong) NULL_LENGTH; + } + if (*pos == 252) + { + if (packet_len < 3) + goto err; + (*packet)+=3; + return (my_ulonglong) uint2korr(pos+1); + } + if (*pos == 253) + { + if (packet_len < 4) + goto err; + (*packet)+=4; + return (my_ulonglong) uint3korr(pos+1); + } + if (packet_len < 9 || *pos != 254) + goto err; + (*packet)+=9; + return (my_ulonglong) uint8korr(pos+1); +err: + *packet = NULL; + return 0; } /* @@ -82,38 +117,69 @@ my_ulonglong net_field_length_ll(uchar **packet) SYNOPSIS net_store_length() - pkg Store the packed integer here + packet Store the packed integer here length integers to store NOTES This is mostly used to store lengths of strings. - We have to cast the result for the LL() becasue of a bug in Forte CC - compiler. RETURN - Position in 'pkg' after the packed length + Position in 'packet' after the packed length */ uchar *net_store_length(uchar *packet, ulonglong length) { - if (length < (ulonglong) 251LL) + if (length < 251) + { + *packet= (uchar) length; + return packet+1; + } + /* 251 is reserved for NULL */ + if (length < 65536) + { + *packet++=252; + int2store(packet, (uint) length); + return packet+2; + } + if (length < 16777216) + { + *packet++=253; + int3store(packet, (ulong) length); + return packet+3; + } + *packet++=254; + int8store(packet,length); + return packet+8; +} + +uchar *safe_net_store_length(uchar *packet, size_t packet_len, ulonglong length) +{ + if (length < 251) { - *packet=(uchar) length; + if (packet_len < 1) + return NULL; + *packet= (uchar) length; return packet+1; } /* 251 is reserved for NULL */ - if (length < (ulonglong) 65536LL) + if (length < 65536) { + if (packet_len < 3) + return NULL; *packet++=252; - int2store(packet,(uint) length); + int2store(packet, (uint) length); return packet+2; } - if (length < (ulonglong) 16777216LL) + if (length < 16777216) { + if (packet_len < 4) + return NULL; *packet++=253; - int3store(packet,(ulong) length); + int3store(packet, (ulong) length); return packet+3; } + if (packet_len < 9) + return NULL; *packet++=254; int8store(packet,length); return packet+8; diff --git a/sql/client_settings.h b/sql/client_settings.h index 5707413f69f..d6a157f71fd 100644 --- a/sql/client_settings.h +++ b/sql/client_settings.h @@ -34,6 +34,7 @@ CLIENT_PROTOCOL_41 | \ CLIENT_SECURE_CONNECTION | \ CLIENT_PLUGIN_AUTH | \ + CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ CLIENT_CONNECT_ATTRS) #define read_user_name(A) {} diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ef189763d88..fc5dfe0994e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2171,129 +2171,28 @@ void Item_func_trim::print(String *str, enum_query_type query_type) /* Item_func_password */ -/** - Helper function for calculating a new password. Used in - Item_func_password::fix_length_and_dec() for const parameters and in - Item_func_password::val_str_ascii() for non-const parameters. - @param str The plain text password which should be digested - @param buffer a pointer to the buffer where the digest will be stored. - - @note The buffer must be of at least CRYPT_MAX_PASSWORD_SIZE size. - - @return Size of the password. -*/ - -static int calculate_password(String *str, char *buffer) -{ - DBUG_ASSERT(str); - if (str->length() == 0) // PASSWORD('') returns '' - return 0; - - int buffer_len= 0; - THD *thd= current_thd; - int old_passwords= 0; - if (thd) - old_passwords= thd->variables.old_passwords; - -#if defined(HAVE_OPENSSL) - if (old_passwords == 2) - { - my_make_scrambled_password(buffer, str->ptr(), - str->length()); - buffer_len= (int) strlen(buffer) + 1; - } - else -#endif - if (old_passwords == 0) - { - my_make_scrambled_password_sha1(buffer, str->ptr(), - str->length()); - buffer_len= SCRAMBLED_PASSWORD_CHAR_LENGTH; - } - else - if (old_passwords == 1) - { - my_make_scrambled_password_323(buffer, str->ptr(), - str->length()); - buffer_len= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; - } - return buffer_len; -} - -/* Item_func_password */ -void Item_func_password::fix_length_and_dec() -{ - maybe_null= false; // PASSWORD() never returns NULL - - if (args[0]->const_item()) - { - String str; - String *res= args[0]->val_str(&str); - if (!args[0]->null_value) - { - m_hashed_password_buffer_len= - calculate_password(res, m_hashed_password_buffer); - fix_length_and_charset(m_hashed_password_buffer_len, default_charset()); - m_recalculate_password= false; - return; - } - } - - m_recalculate_password= true; - fix_length_and_charset(CRYPT_MAX_PASSWORD_SIZE, default_charset()); -} - String *Item_func_password::val_str_ascii(String *str) { DBUG_ASSERT(fixed == 1); - - String *res= args[0]->val_str(str); - - if (args[0]->null_value) - res= make_empty_result(); - - /* we treat NULLs as equal to empty string when calling the plugin */ + String *res= args[0]->val_str(str); check_password_policy(res); - - null_value= 0; - if (args[0]->null_value) // PASSWORD(NULL) returns '' - return res; - - if (m_recalculate_password) - m_hashed_password_buffer_len= calculate_password(res, - m_hashed_password_buffer); - - if (m_hashed_password_buffer_len == 0) + if (args[0]->null_value || res->length() == 0) return make_empty_result(); - - str->set(m_hashed_password_buffer, m_hashed_password_buffer_len, - default_charset()); - + my_make_scrambled_password(tmp_value, res->ptr(), res->length()); + str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1); return str; } -char *Item_func_password:: - create_password_hash_buffer(THD *thd, const char *password, size_t pass_len) +char *Item_func_password::alloc(THD *thd, const char *password, size_t pass_len) { - String *password_str= new (thd->mem_root)String(password, thd->variables. - character_set_client); - check_password_policy(password_str); - - char *buff= NULL; - if (thd->variables.old_passwords == 0) - { - /* Allocate memory for the password scramble and one extra byte for \0 */ - buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH + 1); - my_make_scrambled_password_sha1(buff, password, pass_len); - } -#if defined(HAVE_OPENSSL) - else + char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); + if (buff) { - /* Allocate memory for the password scramble and one extra byte for \0 */ - buff= (char *) thd->alloc(CRYPT_MAX_PASSWORD_SIZE + 1); + String *password_str= new (thd->mem_root)String(password, thd->variables. + character_set_client); + check_password_policy(password_str); my_make_scrambled_password(buff, password, pass_len); } -#endif return buff; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6709b4b64c6..4b9ec50c164 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -21,8 +21,6 @@ /* This file defines all string functions */ -#include "crypt_genhash_impl.h" - #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif @@ -394,21 +392,16 @@ public: class Item_func_password :public Item_str_ascii_func { - char m_hashed_password_buffer[CRYPT_MAX_PASSWORD_SIZE + 1]; - unsigned int m_hashed_password_buffer_len; - bool m_recalculate_password; + char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; public: - Item_func_password(Item *a) :Item_str_ascii_func(a) + Item_func_password(Item *a) :Item_str_ascii_func(a) {} + String *val_str_ascii(String *str); + void fix_length_and_dec() { - m_hashed_password_buffer_len= 0; - m_recalculate_password= false; + fix_length_and_charset(SCRAMBLED_PASSWORD_CHAR_LENGTH, default_charset()); } - String *val_str_ascii(String *str); - void fix_length_and_dec(); const char *func_name() const { return "password"; } static char *alloc(THD *thd, const char *password, size_t pass_len); - static char *create_password_hash_buffer(THD *thd, const char *password, - size_t pass_len); }; diff --git a/sql/password.c b/sql/password.c index 954daf2d8d1..22e0060abd2 100644 --- a/sql/password.c +++ b/sql/password.c @@ -67,7 +67,6 @@ #include <mysql.h> #include <my_rnd.h> #include <sha1.h> -#include <crypt_genhash_impl.h> /************ MySQL 3.23-4.0 authentication routines: untouched ***********/ @@ -280,14 +279,13 @@ void make_password_from_salt_323(char *to, const ulong *salt) **************** MySQL 4.1.1 authentication routines ************* */ -/* - Generate string of printable random characters of requested length - SYNOPSIS - create_random_string() - to OUT buffer for generation; must be at least length+1 bytes - long; result string is always null-terminated - length IN how many random characters to put in buffer - rand_st INOUT structure used for number generation +/** + Generate string of printable random characters of requested length. + + @param to[out] Buffer for generation; must be at least length+1 bytes + long; result string is always null-terminated + length[in] How many random characters to put in buffer + rand_st Structure used for number generation */ void create_random_string(char *to, uint length, @@ -374,23 +372,6 @@ my_crypt(char *to, const uchar *s1, const uchar *s2, uint len) } -#if defined(HAVE_OPENSSL) -void my_make_scrambled_password(char *to, const char *password, - size_t pass_len) -{ - - char salt[CRYPT_SALT_LENGTH + 1]; - - generate_user_salt(salt, CRYPT_SALT_LENGTH + 1); - my_crypt_genhash(to, - CRYPT_MAX_PASSWORD_SIZE, - password, - pass_len, - salt, - 0); - -} -#endif /** Compute two stage SHA1 hash of the password : @@ -422,14 +403,14 @@ void compute_two_stage_sha1_hash(const char *password, size_t pass_len, The result of this function is used as return value from PASSWORD() and is stored in the database. SYNOPSIS - my_make_scrambled_password_sha1() + my_make_scrambled_password() buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string password IN password string pass_len IN length of password string */ -void my_make_scrambled_password_sha1(char *to, const char *password, - size_t pass_len) +void my_make_scrambled_password(char *to, const char *password, + size_t pass_len) { uint8 hash_stage2[SHA1_HASH_SIZE]; @@ -455,7 +436,7 @@ void my_make_scrambled_password_sha1(char *to, const char *password, void make_scrambled_password(char *to, const char *password) { - my_make_scrambled_password_sha1(to, password, strlen(password)); + my_make_scrambled_password(to, password, strlen(password)); } @@ -500,7 +481,7 @@ scramble(char *to, const char *message, const char *password) null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE long (if not, something fishy is going on). SYNOPSIS - check_scramble_sha1() + check_scramble() scramble clients' reply, presumably produced by scramble() message original random string, previously sent to client (presumably second argument of scramble()), must be @@ -514,8 +495,8 @@ scramble(char *to, const char *message, const char *password) */ my_bool -check_scramble_sha1(const uchar *scramble_arg, const char *message, - const uint8 *hash_stage2) +check_scramble(const uchar *scramble_arg, const char *message, + const uint8 *hash_stage2) { uint8 buf[SHA1_HASH_SIZE]; uint8 hash_stage2_reassured[SHA1_HASH_SIZE]; @@ -532,13 +513,6 @@ check_scramble_sha1(const uchar *scramble_arg, const char *message, return test(memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE)); } -my_bool -check_scramble(const uchar *scramble_arg, const char *message, - const uint8 *hash_stage2) -{ - return check_scramble_sha1(scramble_arg, message, hash_stage2); -} - /* Convert scrambled password from asciiz hex string to binary form. @@ -567,3 +541,4 @@ void make_password_from_salt(char *to, const uint8 *hash_stage2) *to++= PVERSION41_CHAR; octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE); } + diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f97b524e843..4ce41e103bd 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -11419,13 +11419,20 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, Cast *passwd to an unsigned char, so that it doesn't extend the sign for *passwd > 127 and become 2**32-127+ after casting to uint. */ - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - (uchar)(*passwd++) : strlen(passwd); - + uint passwd_len; + if (!(thd->client_capabilities & CLIENT_SECURE_CONNECTION)) + passwd_len= strlen(passwd); + else if (!(thd->client_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)) + passwd_len= (uchar)(*passwd++); + else + passwd_len= safe_net_field_length_ll((uchar**)&passwd, + net->read_pos + pkt_len - (uchar*)passwd); + db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? db + passwd_len + 1 : 0; - if (passwd + passwd_len + test(db) > (char *)net->read_pos + pkt_len) + if (passwd == NULL || + passwd + passwd_len + test(db) > (char *)net->read_pos + pkt_len) return packet_error; /* strlen() can't be easily deleted without changing protocol */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 22fa1e53c21..b51cc27c0b0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9753,7 +9753,7 @@ function_call_conflict: | PASSWORD '(' expr ')' { Item* i1; - if (thd->variables.old_passwords == 1) + if (thd->variables.old_passwords) i1= new (thd->mem_root) Item_func_old_password($3); else i1= new (thd->mem_root) Item_func_password($3); @@ -14789,18 +14789,10 @@ text_or_password: TEXT_STRING { $$=$1.str;} | PASSWORD '(' TEXT_STRING ')' { - if ($3.length == 0) - $$= $3.str; - else - switch (thd->variables.old_passwords) { - case 1: $$= Item_func_old_password:: - alloc(thd, $3.str, $3.length); - break; - case 0: - case 2: $$= Item_func_password:: - create_password_hash_buffer(thd, $3.str, $3.length); - break; - } + $$= $3.length ? thd->variables.old_passwords ? + Item_func_old_password::alloc(thd, $3.str, $3.length) : + Item_func_password::alloc(thd, $3.str, $3.length) : + $3.str; if ($$ == NULL) MYSQL_YYABORT; } @@ -15400,7 +15392,7 @@ grant_user: (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); if (buff == NULL) MYSQL_YYABORT; - my_make_scrambled_password_sha1(buff, $4.str, $4.length); + my_make_scrambled_password(buff, $4.str, $4.length); $1->password.str= buff; $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } |