aboutsummaryrefslogtreecommitdiff
path: root/mysql/mysys_ssl
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-11-02 23:11:29 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-11-24 09:33:15 +0300
commit354bb40e75d94466e91fe6960523612c9d17ccfb (patch)
treebdf8b8b90191b98e4b32b62e6cb0e947ea5d5ae2 /mysql/mysys_ssl
parent4bce3c574df293415c7b2f45b9c2951262fe3412 (diff)
Add implementation
Diffstat (limited to 'mysql/mysys_ssl')
-rw-r--r--mysql/mysys_ssl/crypt_genhash_impl.cpp465
-rw-r--r--mysql/mysys_ssl/mf_tempdir.cpp100
-rw-r--r--mysql/mysys_ssl/my_aes.cpp59
-rw-r--r--mysql/mysys_ssl/my_aes_impl.h31
-rw-r--r--mysql/mysys_ssl/my_aes_yassl.cpp244
-rw-r--r--mysql/mysys_ssl/my_default.cpp1523
-rw-r--r--mysql/mysys_ssl/my_default_priv.h43
-rw-r--r--mysql/mysys_ssl/my_getopt.cpp1615
-rw-r--r--mysql/mysys_ssl/my_md5.cpp68
-rw-r--r--mysql/mysys_ssl/my_murmur3.cpp134
-rw-r--r--mysql/mysys_ssl/my_rnd.cpp115
-rw-r--r--mysql/mysys_ssl/my_sha1.cpp141
-rw-r--r--mysql/mysys_ssl/my_sha2.cpp68
13 files changed, 4606 insertions, 0 deletions
diff --git a/mysql/mysys_ssl/crypt_genhash_impl.cpp b/mysql/mysys_ssl/crypt_genhash_impl.cpp
new file mode 100644
index 0000000..80b61dc
--- /dev/null
+++ b/mysql/mysys_ssl/crypt_genhash_impl.cpp
@@ -0,0 +1,465 @@
+/* Copyright (c) 2011, 2015, 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 02110-1301 USA */
+
+
+// First include (the generated) my_config.h, to get correct platform defines.
+#include "my_config.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 "m_string.h"
+
+#include <stdint.h>
+#include <time.h>
+#include <string.h>
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#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_t 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 uint 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_t) 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,
+ size_t plaintext_len,
+ const char *switchsalt,
+ const char **params)
+{
+ int salt_len;
+ size_t 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;
+ uint 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(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 < 16U + (uint8_t)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) my_snprintf(ctbuffer, ctbufflen,
+ "%s$rounds=%zu$", crypt_alg_magic, (size_t)rounds);
+ }
+ else
+ {
+ (void) my_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/mysql/mysys_ssl/mf_tempdir.cpp b/mysql/mysys_ssl/mf_tempdir.cpp
new file mode 100644
index 0000000..2935509
--- /dev/null
+++ b/mysql/mysys_ssl/mf_tempdir.cpp
@@ -0,0 +1,100 @@
+/* Copyright (c) 2000, 2014, 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 02110-1301 USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include "prealloced_array.h"
+#include "mutex_lock.h"
+
+#if defined(_WIN32)
+#define DELIM ';'
+#else
+#define DELIM ':'
+#endif
+
+my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist)
+{
+ char *end, *copy;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("init_tmpdir");
+ DBUG_PRINT("enter", ("pathlist: %s", pathlist ? pathlist : "NULL"));
+
+ Prealloced_array<char*, 10, true> full_list(key_memory_MY_TMPDIR_full_list);
+
+ memset(tmpdir, 0, sizeof(*tmpdir));
+ if (!pathlist || !pathlist[0])
+ {
+ /* Get default temporary directory */
+ pathlist=getenv("TMPDIR"); /* Use this if possible */
+#if defined(_WIN32)
+ if (!pathlist)
+ pathlist=getenv("TEMP");
+ if (!pathlist)
+ pathlist=getenv("TMP");
+#endif
+ if (!pathlist || !pathlist[0])
+ pathlist= DEFAULT_TMPDIR;
+ }
+ do
+ {
+ size_t length;
+ end=strcend(pathlist, DELIM);
+ strmake(buff, pathlist, (uint) (end-pathlist));
+ length= cleanup_dirname(buff, buff);
+ if (!(copy= my_strndup(key_memory_MY_TMPDIR_full_list,
+ buff, length, MYF(MY_WME))) ||
+ full_list.push_back(copy))
+ DBUG_RETURN(TRUE);
+ pathlist=end+1;
+ }
+ while (*end);
+
+ tmpdir->list=
+ static_cast<char**>(my_malloc(key_memory_MY_TMPDIR_full_list,
+ sizeof(char*) * full_list.size(),
+ MYF(MY_WME)));
+ if (tmpdir->list == NULL)
+ DBUG_RETURN(TRUE);
+
+ mysql_mutex_init(key_TMPDIR_mutex, &tmpdir->mutex, MY_MUTEX_INIT_FAST);
+ memcpy(tmpdir->list, &full_list[0], sizeof(char*) * full_list.size());
+ tmpdir->max= full_list.size() - 1;
+ tmpdir->cur= 0;
+ DBUG_RETURN(FALSE);
+}
+
+
+char *my_tmpdir(MY_TMPDIR *tmpdir)
+{
+ if (0 == tmpdir->max)
+ return tmpdir->list[0];
+
+ Mutex_lock(&tmpdir->mutex);
+ char *dir= tmpdir->list[tmpdir->cur];
+ tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur + 1;
+
+ return dir;
+}
+
+
+void free_tmpdir(MY_TMPDIR *tmpdir)
+{
+ if (tmpdir->list == NULL)
+ return;
+ for (uint i= 0; i <= tmpdir->max; i++)
+ my_free(tmpdir->list[i]);
+ my_free(tmpdir->list);
+ mysql_mutex_destroy(&tmpdir->mutex);
+}
diff --git a/mysql/mysys_ssl/my_aes.cpp b/mysql/mysys_ssl/my_aes.cpp
new file mode 100644
index 0000000..f5ebe8b
--- /dev/null
+++ b/mysql/mysys_ssl/my_aes.cpp
@@ -0,0 +1,59 @@
+/* Copyright (c) 2002, 2014, 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 02110-1301 USA */
+
+
+#include <my_global.h>
+#include <m_string.h>
+#include <my_aes.h>
+#include "my_aes_impl.h"
+
+
+/**
+ Transforms an arbitrary long key into a fixed length AES key
+
+ AES keys are of fixed length. This routine takes an arbitrary long key
+ iterates over it in AES key length increment and XORs the bytes with the
+ AES key buffer being prepared.
+ The bytes from the last incomplete iteration are XORed to the start
+ of the key until their depletion.
+ Needed since crypto function routines expect a fixed length key.
+
+ @param key [in] Key to use for real key creation
+ @param key_length [in] Length of the key
+ @param rkey [out] Real key (used by OpenSSL/YaSSL)
+ @param opmode [out] encryption mode
+*/
+
+void my_aes_create_key(const unsigned char *key, uint key_length,
+ uint8 *rkey, enum my_aes_opmode opmode)
+{
+ const uint key_size= my_aes_opmode_key_sizes[opmode] / 8;
+ uint8 *rkey_end; /* Real key boundary */
+ uint8 *ptr; /* Start of the real key*/
+ uint8 *sptr; /* Start of the working key */
+ uint8 *key_end= ((uint8 *)key) + key_length; /* Working key boundary*/
+
+ rkey_end= rkey + key_size;
+
+ memset(rkey, 0, key_size); /* Set initial key */
+
+ for (ptr= rkey, sptr= (uint8 *)key; sptr < key_end; ptr++, sptr++)
+ {
+ if (ptr == rkey_end)
+ /* Just loop over tmp_key until we used all key */
+ ptr= rkey;
+ *ptr^= *sptr;
+ }
+}
diff --git a/mysql/mysys_ssl/my_aes_impl.h b/mysql/mysys_ssl/my_aes_impl.h
new file mode 100644
index 0000000..2e18b2e
--- /dev/null
+++ b/mysql/mysys_ssl/my_aes_impl.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2014, 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 02110-1301 USA */
+
+
+/** Maximum supported key kength */
+#define MAX_AES_KEY_LENGTH 256
+
+/* TODO: remove in a future version */
+/* Guard against using an old export control restriction #define */
+#ifdef AES_USE_KEY_BITS
+#error AES_USE_KEY_BITS not supported
+#endif
+
+extern uint *my_aes_opmode_key_sizes;
+
+
+void my_aes_create_key(const unsigned char *key, uint key_length,
+ uint8 *rkey, enum my_aes_opmode opmode);
+
diff --git a/mysql/mysys_ssl/my_aes_yassl.cpp b/mysql/mysys_ssl/my_aes_yassl.cpp
new file mode 100644
index 0000000..f387e34
--- /dev/null
+++ b/mysql/mysys_ssl/my_aes_yassl.cpp
@@ -0,0 +1,244 @@
+/* Copyright (c) 2015, 2016 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 02110-1301 USA */
+
+#include <my_global.h>
+#include <m_string.h>
+#include <my_aes.h>
+#include "my_aes_impl.h"
+
+#include "aes.hpp"
+#include "openssl/ssl.h"
+
+/* keep in sync with enum my_aes_opmode in my_aes.h */
+const char *my_aes_opmode_names[]=
+{
+ "aes-128-ecb",
+ "aes-192-ecb",
+ "aes-256-ecb",
+ "aes-128-cbc",
+ "aes-192-cbc",
+ "aes-256-cbc",
+ NULL /* needed for the type enumeration */
+};
+
+
+/* keep in sync with enum my_aes_opmode in my_aes.h */
+static uint my_aes_opmode_key_sizes_impl[]=
+{
+ 128 /* aes-128-ecb */,
+ 192 /* aes-192-ecb */,
+ 256 /* aes-256-ecb */,
+ 128 /* aes-128-cbc */,
+ 192 /* aes-192-cbc */,
+ 256 /* aes-256-cbc */,
+};
+
+uint *my_aes_opmode_key_sizes= my_aes_opmode_key_sizes_impl;
+
+
+template <TaoCrypt::CipherDir DIR>
+class MyCipherCtx
+{
+public:
+ MyCipherCtx(enum my_aes_opmode mode) : m_mode(mode)
+ {
+ switch (m_mode)
+ {
+ case my_aes_128_ecb:
+ case my_aes_192_ecb:
+ case my_aes_256_ecb:
+ m_need_iv= false;
+ break;
+ default:
+ m_need_iv= true;
+ break;
+ }
+ }
+
+ bool SetKey(const unsigned char *key, uint block_size,
+ const unsigned char *iv)
+ {
+ if (m_need_iv)
+ {
+ if (!iv)
+ return TRUE;
+ cbc.SetKey(key, block_size, iv);
+ }
+ else
+ ecb.SetKey(key, block_size);
+ return false;
+ }
+
+ void Process(unsigned char *dest, const unsigned char * source,
+ uint block_size)
+ {
+ if (m_need_iv)
+ cbc.Process(dest, source, block_size);
+ else
+ ecb.Process(dest, source, block_size);
+ }
+
+ bool needs_iv() const
+ {
+ return m_need_iv;
+ }
+
+private:
+ /* we initialize the two classes to avoid dynamic allocation */
+ TaoCrypt::BlockCipher<DIR, TaoCrypt::AES, TaoCrypt::ECB> ecb;
+ TaoCrypt::BlockCipher<DIR, TaoCrypt::AES, TaoCrypt::CBC> cbc;
+ enum my_aes_opmode m_mode;
+ bool m_need_iv;
+};
+
+
+int my_aes_encrypt(const unsigned char *source, uint32 source_length,
+ unsigned char *dest,
+ const unsigned char *key, uint32 key_length,
+ enum my_aes_opmode mode, const unsigned char *iv,
+ bool padding)
+{
+ MyCipherCtx<TaoCrypt::ENCRYPTION> enc(mode);
+
+ /* 128 bit block used for padding */
+ unsigned char block[MY_AES_BLOCK_SIZE];
+ uint num_blocks; /* number of complete blocks */
+ uint i;
+ /* predicted real key size */
+ const uint key_size= my_aes_opmode_key_sizes[mode] / 8;
+ /* The real key to be used for encryption */
+ unsigned char rkey[MAX_AES_KEY_LENGTH / 8];
+
+ my_aes_create_key(key, key_length, rkey, mode);
+
+ if (enc.SetKey(rkey, key_size, iv))
+ return MY_AES_BAD_DATA;
+
+ num_blocks= source_length / MY_AES_BLOCK_SIZE;
+
+ /* Encode all complete blocks */
+ for (i = num_blocks; i > 0;
+ i--, source+= MY_AES_BLOCK_SIZE, dest+= MY_AES_BLOCK_SIZE)
+ enc.Process(dest, source, MY_AES_BLOCK_SIZE);
+
+ /* If no padding, return here */
+ if (!padding)
+ return (int) (MY_AES_BLOCK_SIZE * num_blocks);
+ /*
+ Re-implement standard PKCS padding for the last block.
+ Pad the last incomplete data block (even if empty) with bytes
+ equal to the size of extra padding stored into that last packet.
+ This also means that there will always be one more block,
+ even if the source data size is dividable by the AES block size.
+ */
+ unsigned char pad_len=
+ MY_AES_BLOCK_SIZE - (source_length - MY_AES_BLOCK_SIZE * num_blocks);
+ memcpy(block, source, MY_AES_BLOCK_SIZE - pad_len);
+ memset(block + MY_AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
+
+ enc.Process(dest, block, MY_AES_BLOCK_SIZE);
+
+ /* we've added a block */
+ num_blocks+= 1;
+
+ return (int) (MY_AES_BLOCK_SIZE * num_blocks);
+}
+
+int my_aes_decrypt(const unsigned char *source, uint32 source_length,
+ unsigned char *dest,
+ const unsigned char *key, uint32 key_length,
+ enum my_aes_opmode mode, const unsigned char *iv,
+ bool padding)
+{
+ MyCipherCtx<TaoCrypt::DECRYPTION> dec(mode);
+ /* 128 bit block used for padding */
+ uint8 block[MY_AES_BLOCK_SIZE];
+ uint32 num_blocks; /* Number of complete blocks */
+ int i;
+ /* predicted real key size */
+ const uint key_size= my_aes_opmode_key_sizes[mode] / 8;
+ /* The real key to be used for decryption */
+ unsigned char rkey[MAX_AES_KEY_LENGTH / 8];
+
+ my_aes_create_key(key, key_length, rkey, mode);
+ dec.SetKey(rkey, key_size, iv);
+
+ num_blocks= source_length / MY_AES_BLOCK_SIZE;
+
+ /*
+ Input size has to be a multiple of the AES block size.
+ And, due to the standard PKCS padding, at least one block long.
+ */
+ if ((source_length != num_blocks * MY_AES_BLOCK_SIZE) || num_blocks == 0)
+ return MY_AES_BAD_DATA;
+
+ /* Decode all but the last block */
+ for (i= padding? num_blocks - 1: num_blocks; i > 0;
+ i--, source+= MY_AES_BLOCK_SIZE, dest+= MY_AES_BLOCK_SIZE)
+ dec.Process(dest, source, MY_AES_BLOCK_SIZE);
+
+ /* If no padding, return here. */
+ if (!padding)
+ return MY_AES_BLOCK_SIZE * num_blocks;
+
+ /* unwarp the standard PKCS padding */
+ dec.Process(block, source, MY_AES_BLOCK_SIZE);
+
+ /* Use last char in the block as size */
+ uint8 pad_len = block[MY_AES_BLOCK_SIZE - 1];
+
+ if (pad_len > MY_AES_BLOCK_SIZE)
+ return MY_AES_BAD_DATA;
+ /* We could also check whole padding but we do not really need this */
+
+ memcpy(dest, block, MY_AES_BLOCK_SIZE - pad_len);
+ return MY_AES_BLOCK_SIZE * num_blocks - pad_len;
+}
+
+/**
+ Get size of buffer which will be large enough for encrypted data
+
+ SYNOPSIS
+ my_aes_get_size()
+ @param source_length [in] Length of data to be encrypted
+ @param mode encryption mode
+
+ @return Size of buffer required to store encrypted data
+*/
+
+int my_aes_get_size(uint32 source_length, my_aes_opmode opmode)
+{
+ return MY_AES_BLOCK_SIZE * (source_length / MY_AES_BLOCK_SIZE)
+ + MY_AES_BLOCK_SIZE;
+}
+
+/**
+ Return true if the AES cipher and block mode requires an IV
+
+ SYNOPSIS
+ my_aes_needs_iv()
+ @param mode encryption mode
+
+ @retval TRUE IV needed
+ @retval FALSE IV not needed
+*/
+
+my_bool my_aes_needs_iv(my_aes_opmode opmode)
+{
+ MyCipherCtx<TaoCrypt::ENCRYPTION> enc(opmode);
+
+ return enc.needs_iv() ? TRUE : FALSE;
+}
+
diff --git a/mysql/mysys_ssl/my_default.cpp b/mysql/mysys_ssl/my_default.cpp
new file mode 100644
index 0000000..5a45200
--- /dev/null
+++ b/mysql/mysys_ssl/my_default.cpp
@@ -0,0 +1,1523 @@
+/* Copyright (c) 2000, 2016, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
+
+/****************************************************************************
+ Add all options from files named "group".cnf from the default_directories
+ before the command line arguments.
+ On Windows defaults will also search in the Windows directory for a file
+ called 'group'.ini
+ As long as the program uses the last argument for conflicting
+ options one only have to add a call to "load_defaults" to enable
+ use of default values.
+ pre- and end 'blank space' are removed from options and values. The
+ following escape sequences are recognized in values: \b \t \n \r \\
+
+ The following arguments are handled automatically; If used, they must be
+ first argument on the command line!
+ --no-defaults ; no options are read, except for the ones provided in the
+ login file.
+ --defaults-file=full-path-to-default-file ; Only this file will be read.
+ --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
+ --defaults-group-suffix ; Also read groups with concat(group, suffix)
+ --print-defaults ; Print the modified command line and exit
+ --login-path=login-path-name ; Read options under login-path-name from
+ the login file.
+****************************************************************************/
+
+#include "../mysys/mysys_priv.h"
+#include "my_default.h"
+#include "my_default_priv.h"
+#include "m_string.h"
+#include "m_ctype.h"
+#include <my_dir.h>
+#include <my_aes.h>
+#include "mysql/psi/mysql_file.h"
+#ifdef _WIN32
+#include <winbase.h>
+#endif
+
+#include "prealloced_array.h"
+
+C_MODE_START
+#ifdef HAVE_PSI_INTERFACE
+extern PSI_file_key key_file_cnf;
+#endif
+PSI_memory_key key_memory_defaults;
+C_MODE_END
+
+/**
+ arguments separator
+
+ load_defaults() loads arguments from config file and put them
+ before the arguments from command line, this separator is used to
+ separate the arguments loaded from config file and arguments user
+ provided on command line.
+
+ Options with value loaded from config file are always in the form
+ '--option=value', while for command line options, the value can be
+ given as the next argument. Thus we used a separator so that
+ handle_options() can distinguish them.
+
+ Note: any other places that does not need to distinguish them
+ should skip the separator.
+
+ The content of arguments separator does not matter, one should only
+ check the pointer, use "----args-separator----" here to ease debug
+ if someone misused it.
+
+ The args seprator will only be added when
+ my_getopt_use_args_seprator is set to TRUE before calling
+ load_defaults();
+
+ See BUG#25192
+*/
+static const char *args_separator= "----args-separator----";
+inline static void set_args_separator(char** arg)
+{
+ DBUG_ASSERT(my_getopt_use_args_separator);
+ *arg= (char*)args_separator;
+}
+
+/*
+ This flag indicates that the argument separator string
+ (args_separator) should be added to the list of arguments,
+ in order to separate arguments received from config file
+ and command line.
+*/
+my_bool my_getopt_use_args_separator= FALSE;
+my_bool my_getopt_is_args_separator(const char* arg)
+{
+ return (arg == args_separator);
+}
+const char *my_defaults_file=0;
+const char *my_defaults_group_suffix=0;
+const char *my_defaults_extra_file=0;
+
+static const char *my_login_path= 0;
+
+static char my_defaults_file_buffer[FN_REFLEN];
+static char my_defaults_extra_file_buffer[FN_REFLEN];
+
+static my_bool defaults_already_read= FALSE;
+
+/* Which directories are searched for options (and in which order) */
+
+#define MAX_DEFAULT_DIRS 6
+#define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1) /* Terminate with NULL */
+static const char **default_directories = NULL;
+
+#ifdef _WIN32
+static const char *f_extensions[]= { ".ini", ".cnf", 0 };
+#define NEWLINE "\r\n"
+#else
+static const char *f_extensions[]= { ".cnf", 0 };
+#define NEWLINE "\n"
+#endif
+
+extern "C" {
+static int handle_default_option(void *in_ctx, const char *group_name,
+ const char *option);
+}
+
+/*
+ This structure defines the context that we pass to callback
+ function 'handle_default_option' used in search_default_file
+ to process each option. This context is used if search_default_file
+ was called from load_defaults.
+*/
+
+typedef Prealloced_array<char*, 100> My_args;
+struct handle_option_ctx
+{
+ MEM_ROOT *alloc;
+ My_args *m_args;
+ TYPELIB *group;
+};
+
+static int search_default_file(Process_option_func func, void *func_ctx,
+ const char *dir, const char *config_file,
+ my_bool is_login_file);
+static int search_default_file_with_ext(Process_option_func func,
+ void *func_ctx,
+ const char *dir, const char *ext,
+ const char *config_file,
+ int recursion_level,
+ my_bool is_login_file);
+static my_bool mysql_file_getline(char *str, int size, MYSQL_FILE *file,
+ my_bool is_login_file);
+
+/**
+ Create the list of default directories.
+
+ @param alloc MEM_ROOT where the list of directories is stored
+
+ @details
+ The directories searched, in order, are:
+ - Windows: GetSystemWindowsDirectory()
+ - Windows: GetWindowsDirectory()
+ - Windows: C:/
+ - Windows: Directory above where the executable is located
+ - Unix: /etc/
+ - Unix: /etc/mysql/
+ - Unix: --sysconfdir=<path> (compile-time option)
+ - ALL: getenv("MYSQL_HOME")
+ - ALL: --defaults-extra-file=<path> (run-time option)
+ - Unix: ~/
+
+ On all systems, if a directory is already in the list, it will be moved
+ to the end of the list. This avoids reading defaults files multiple times,
+ while ensuring the correct precedence.
+
+ @retval NULL Failure (out of memory, probably)
+ @retval other Pointer to NULL-terminated array of default directories
+*/
+
+static const char **init_default_directories(MEM_ROOT *alloc);
+
+
+static char *remove_end_comment(char *ptr);
+
+
+/*
+ Expand a file name so that the current working directory is added if
+ the name is relative.
+
+ RETURNS
+ 0 All OK
+ 2 Out of memory or path too long
+ 3 Not able to get working directory
+ */
+
+static int
+fn_expand(const char *filename, char *result_buf)
+{
+ char dir[FN_REFLEN];
+ const int flags= MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_RELATIVE_PATH;
+ DBUG_ENTER("fn_expand");
+ DBUG_PRINT("enter", ("filename: %s, result_buf: 0x%lx",
+ filename, (unsigned long) result_buf));
+ if (my_getwd(dir, sizeof(dir), MYF(0)))
+ DBUG_RETURN(3);
+ DBUG_PRINT("debug", ("dir: %s", dir));
+ if (fn_format(result_buf, filename, dir, "", flags) == NULL)
+ DBUG_RETURN(2);
+ DBUG_PRINT("return", ("result: %s", result_buf));
+ DBUG_RETURN(0);
+}
+
+/*
+ Process config files in default directories.
+
+ SYNOPSIS
+ my_search_option_files()
+ conf_file Basename for configuration file to search for.
+ If this is a path, then only this file is read.
+ argc Pointer to argc of original program
+ argv Pointer to argv of original program
+ args_used Pointer to variable for storing the number of
+ arguments used.
+ func Pointer to the function to process options
+ func_ctx It's context. Usually it is the structure to
+ store additional options.
+ default_directories List of default directories.
+ found_no_defaults TRUE, if --no-defaults is specified.
+
+ DESCRIPTION
+ Process the default options from argc & argv
+ Read through each found config file looks and calls 'func' to process
+ each option. This function also reads options from login file.
+
+ NOTES
+ --defaults-group-suffix is only processed if we are called from
+ load_defaults().
+
+
+ RETURN
+ 0 ok
+ 1 given cinf_file doesn't exist
+ 2 out of memory
+ 3 Can't get current working directory
+
+ The global variable 'my_defaults_group_suffix' is updated with value for
+ --defaults_group_suffix
+*/
+
+int my_search_option_files(const char *conf_file, int *argc, char ***argv,
+ uint *args_used, Process_option_func func,
+ void *func_ctx, const char **default_directories,
+ my_bool is_login_file, my_bool found_no_defaults)
+{
+ const char **dirs, *forced_default_file, *forced_extra_defaults;
+ int error= 0;
+ DBUG_ENTER("my_search_option_files");
+
+ /* Skip for login file. */
+ if (! is_login_file)
+ {
+ /* Check if we want to force the use a specific default file */
+ *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
+ (char **) &forced_default_file,
+ (char **) &forced_extra_defaults,
+ (char **) &my_defaults_group_suffix,
+ (char **) &my_login_path, found_no_defaults);
+
+ if (! my_defaults_group_suffix)
+ my_defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV));
+
+ if (forced_extra_defaults && !defaults_already_read)
+ {
+ int error= fn_expand(forced_extra_defaults,
+ my_defaults_extra_file_buffer);
+ if (error)
+ DBUG_RETURN(error);
+
+ my_defaults_extra_file= my_defaults_extra_file_buffer;
+ }
+
+ if (forced_default_file && !defaults_already_read)
+ {
+ int error= fn_expand(forced_default_file, my_defaults_file_buffer);
+ if (error)
+ DBUG_RETURN(error);
+ my_defaults_file= my_defaults_file_buffer;
+ }
+
+ defaults_already_read= TRUE;
+
+ /*
+ We can only handle 'defaults-group-suffix' if we are called from
+ load_defaults() as otherwise we can't know the type of 'func_ctx'
+ */
+
+ if (my_defaults_group_suffix && func == handle_default_option)
+ {
+ /* Handle --defaults-group-suffix= */
+ uint i;
+ const char **extra_groups;
+ const size_t instance_len= strlen(my_defaults_group_suffix);
+ struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
+ char *ptr;
+ TYPELIB *group= ctx->group;
+
+ if (!(extra_groups=
+ (const char**)alloc_root(ctx->alloc,
+ (2*group->count+1)*sizeof(char*))))
+ DBUG_RETURN(2);
+
+ for (i= 0; i < group->count; i++)
+ {
+ size_t len;
+ extra_groups[i]= group->type_names[i]; /** copy group */
+
+ len= strlen(extra_groups[i]);
+ if (!(ptr= (char *) alloc_root(ctx->alloc,
+ (uint) (len + instance_len + 1))))
+ DBUG_RETURN(2);
+
+ extra_groups[i+group->count]= ptr;
+
+ /** Construct new group */
+ memcpy(ptr, extra_groups[i], len);
+ memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
+ }
+
+ group->count*= 2;
+ group->type_names= extra_groups;
+ group->type_names[group->count]= 0;
+ }
+ }
+ else if (my_login_path && func == handle_default_option)
+ {
+ /* Handle --login_path= */
+ uint i;
+ size_t len;
+ const char **extra_groups;
+ size_t instance_len= 0;
+ struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
+ char *ptr;
+ TYPELIB *group= ctx->group;
+
+ if (!(extra_groups= (const char**)alloc_root(ctx->alloc,
+ (group->count + 3)
+ * sizeof(char *))))
+ DBUG_RETURN(2);
+
+ for (i= 0; i < group->count; i++)
+ {
+ extra_groups[i]= group->type_names[i]; /** copy group */
+ }
+
+ extra_groups[i]= my_login_path;
+
+ if (my_defaults_group_suffix && func == handle_default_option)
+ {
+ instance_len= strlen(my_defaults_group_suffix);
+ len= strlen(extra_groups[i]);
+
+ if (!(ptr= (char *) alloc_root(ctx->alloc,
+ (uint) (len + instance_len + 1))))
+ DBUG_RETURN(2);
+
+ extra_groups[i + 1]= ptr;
+
+ /** Construct new group */
+ memcpy(ptr, extra_groups[i], len);
+ memcpy(ptr+len, my_defaults_group_suffix, instance_len + 1);
+ group->count += 1;
+ }
+
+ group->count += 1;
+ group->type_names= extra_groups;
+ group->type_names[group->count]= 0;
+ }
+
+ // If conf_file is an absolute path, we only read it
+ if (dirname_length(conf_file))
+ {
+ if ((error= search_default_file(func, func_ctx, NullS, conf_file,
+ is_login_file)) < 0)
+ goto err;
+ }
+ // If my defaults file is set (from a previous run), we read it
+ else if (my_defaults_file)
+ {
+ if ((error= search_default_file_with_ext(func, func_ctx, "", "",
+ my_defaults_file, 0,
+ is_login_file)) < 0)
+ goto err;
+ if (error > 0)
+ {
+ my_message_local(ERROR_LEVEL,
+ "Could not open required defaults file: %s",
+ my_defaults_file);
+ goto err;
+ }
+ }
+ else if (! found_no_defaults)
+ {
+ for (dirs= default_directories ; *dirs; dirs++)
+ {
+ if (**dirs)
+ {
+ if (search_default_file(func, func_ctx, *dirs, conf_file,
+ is_login_file) < 0)
+ goto err;
+ }
+ else if (my_defaults_extra_file)
+ {
+ if ((error= search_default_file_with_ext(func, func_ctx, "", "",
+ my_defaults_extra_file, 0,
+ is_login_file)) < 0)
+ goto err; /* Fatal error */
+ if (error > 0)
+ {
+ my_message_local(ERROR_LEVEL,
+ "Could not open required defaults file: %s",
+ my_defaults_extra_file);
+ goto err;
+ }
+ }
+ }
+ }
+
+ DBUG_RETURN(0);
+
+err:
+ my_message_local(ERROR_LEVEL,
+ "Fatal error in defaults handling. Program aborted!");
+ DBUG_RETURN(1);
+}
+
+
+/*
+ The option handler for load_defaults.
+
+ SYNOPSIS
+ handle_deault_option()
+ in_ctx Handler context. In this case it is a
+ handle_option_ctx structure.
+ group_name The name of the group the option belongs to.
+ option The very option to be processed. It is already
+ prepared to be used in argv (has -- prefix). If it
+ is NULL, we are handling a new group (section).
+
+ DESCRIPTION
+ This handler checks whether a group is one of the listed and adds an option
+ to the array if yes. Some other handler can record, for instance, all
+ groups and their options, not knowing in advance the names and amount of
+ groups.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+static int handle_default_option(void *in_ctx, const char *group_name,
+ const char *option)
+{
+ char *tmp;
+ struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
+
+ if (!option)
+ return 0;
+
+ if (find_type((char *)group_name, ctx->group, FIND_TYPE_NO_PREFIX))
+ {
+ if (!(tmp= (char *) alloc_root(ctx->alloc, strlen(option) + 1)))
+ return 1;
+ if (ctx->m_args->push_back(tmp))
+ return 1;
+ my_stpcpy(tmp, option);
+ }
+
+ return 0;
+}
+
+
+/*
+ Gets options from the command line, however if --no-defaults
+ option is used, --defaults-file & --defaults-extra-file options
+ would be ignored.
+
+ SYNOPSIS
+ get_defaults_options()
+ argc Pointer to argc of original program
+ argv Pointer to argv of original program
+ defaults --defaults-file option
+ extra_defaults --defaults-extra-file option
+ group_suffix --defaults-group-suffix option
+ login_path --login-path option
+
+ RETURN
+ # Number of arguments used from *argv
+ defaults and extra_defaults will be set to option of the appropriate
+ items of argv array, or to NULL if there are no such options
+*/
+
+int get_defaults_options(int argc, char **argv,
+ char **defaults,
+ char **extra_defaults,
+ char **group_suffix,
+ char **login_path,
+ my_bool found_no_defaults)
+{
+ int org_argc= argc, prev_argc= 0, default_option_count= 0;
+ *defaults= *extra_defaults= *group_suffix= *login_path= 0;
+
+ while (argc >= 2 && argc != prev_argc)
+ {
+ /* Skip program name or previously handled argument */
+ argv++;
+ prev_argc= argc; /* To check if we found */
+ /* --no-defaults is always the first option. */
+ if (is_prefix(*argv,"--no-defaults") && ! default_option_count)
+ {
+ argc--;
+ default_option_count ++;
+ continue;
+ }
+ if (!*defaults && is_prefix(*argv, "--defaults-file=") && ! found_no_defaults)
+ {
+ *defaults= *argv + sizeof("--defaults-file=")-1;
+ argc--;
+ default_option_count ++;
+ continue;
+ }
+ if (!*extra_defaults && is_prefix(*argv, "--defaults-extra-file=")
+ && ! found_no_defaults)
+ {
+ *extra_defaults= *argv + sizeof("--defaults-extra-file=")-1;
+ argc--;
+ default_option_count ++;
+ continue;
+ }
+ if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix="))
+ {
+ *group_suffix= *argv + sizeof("--defaults-group-suffix=")-1;
+ argc--;
+ default_option_count ++;
+ continue;
+ }
+ if (!*login_path && is_prefix(*argv, "--login-path="))
+ {
+ *login_path= *argv + sizeof("--login-path=")-1;
+ argc--;
+ default_option_count ++;
+ continue;
+ }
+ }
+ return org_argc - argc;
+}
+
+/*
+ Wrapper around my_load_defaults() for interface compatibility.
+
+ SYNOPSIS
+ load_defaults()
+ conf_file Basename for configuration file to search for.
+ If this is a path, then only this file is read.
+ groups Which [group] entrys to read.
+ Points to an null terminated array of pointers
+ argc Pointer to argc of original program
+ argv Pointer to argv of original program
+
+ NOTES
+
+ This function is NOT thread-safe as it uses a global pointer internally.
+ See also notes for my_load_defaults().
+
+ RETURN
+ 0 ok
+ 1 The given conf_file didn't exists
+*/
+int load_defaults(const char *conf_file, const char **groups,
+ int *argc, char ***argv)
+{
+ return my_load_defaults(conf_file, groups, argc, argv, &default_directories);
+}
+
+/** A global to turn off or on reading the mylogin file. On by default */
+my_bool my_defaults_read_login_file= TRUE;
+/*
+ Read options from configurations files
+
+ SYNOPSIS
+ my_load_defaults()
+ conf_file Basename for configuration file to search for.
+ If this is a path, then only this file is read.
+ groups Which [group] entrys to read.
+ Points to an null terminated array of pointers
+ argc Pointer to argc of original program
+ argv Pointer to argv of original program
+ default_directories Pointer to a location where a pointer to the list
+ of default directories will be stored
+
+ IMPLEMENTATION
+
+ Read options from configuration files and put them BEFORE the arguments
+ that are already in argc and argv. This way the calling program can
+ easily command line options override options in configuration files
+
+ NOTES
+ In case of fatal error, the function will print a warning and do
+ exit(1)
+
+ To free used memory one should call free_defaults() with the argument
+ that was put in *argv
+
+ RETURN
+ - If successful, 0 is returned. If 'default_directories' is not NULL,
+ a pointer to the array of default directory paths is stored to a location
+ it points to. That stored value must be passed to my_search_option_files()
+ later.
+
+ - 1 is returned if the given conf_file didn't exist. In this case, the
+ value pointed to by default_directories is undefined.
+*/
+
+
+int my_load_defaults(const char *conf_file, const char **groups,
+ int *argc, char ***argv, const char ***default_directories)
+{
+ My_args my_args(key_memory_defaults);
+ TYPELIB group;
+ my_bool found_print_defaults= 0;
+ uint args_used= 0;
+ int error= 0;
+ MEM_ROOT alloc;
+ char *ptr,**res;
+ struct handle_option_ctx ctx;
+ const char **dirs;
+ char my_login_file[FN_REFLEN];
+ my_bool found_no_defaults= false;
+ uint args_sep= my_getopt_use_args_separator ? 1 : 0;
+ DBUG_ENTER("load_defaults");
+
+ init_alloc_root(key_memory_defaults, &alloc,512,0);
+ if ((dirs= init_default_directories(&alloc)) == NULL)
+ goto err;
+ /*
+ Check if the user doesn't want any default option processing
+ --no-defaults is always the first option
+ */
+ if (*argc >= 2 && !strcmp(argv[0][1], "--no-defaults"))
+ found_no_defaults= TRUE;
+
+ group.count=0;
+ group.name= "defaults";
+ group.type_names= groups;
+
+ for (; *groups ; groups++)
+ group.count++;
+
+ ctx.alloc= &alloc;
+ ctx.m_args= &my_args;
+ ctx.group= &group;
+
+ if ((error= my_search_option_files(conf_file, argc, argv,
+ &args_used, handle_default_option,
+ (void *) &ctx, dirs, false, found_no_defaults)))
+ {
+ free_root(&alloc,MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ if (my_defaults_read_login_file)
+ {
+ /* Read options from login group. */
+ if (my_default_get_login_file(my_login_file, sizeof(my_login_file)) &&
+ (error= my_search_option_files(my_login_file, argc, argv, &args_used,
+ handle_default_option, (void *) &ctx,
+ dirs, true, found_no_defaults)))
+ {
+ free_root(&alloc, MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+ /*
+ Here error contains <> 0 only if we have a fully specified conf_file
+ or a forced default file
+ */
+ if (!(ptr=(char*)
+ alloc_root(&alloc,sizeof(alloc)+
+ (my_args.size() + *argc + 1 + args_sep) *sizeof(char*))))
+ goto err;
+ res= (char**) (ptr+sizeof(alloc));
+
+ /* copy name + found arguments + command line arguments to new array */
+ res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
+ if (!my_args.empty())
+ memcpy((res+1), &my_args[0], my_args.size() * sizeof(char*));
+ /* Skip --defaults-xxx options */
+ (*argc)-= args_used;
+ (*argv)+= args_used;
+
+ /*
+ Check if we wan't to see the new argument list
+ This options must always be the last of the default options
+ */
+ if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
+ {
+ found_print_defaults=1;
+ --*argc; ++*argv; /* skip argument */
+ }
+
+ if (my_getopt_use_args_separator)
+ {
+ /* set arguments separator for arguments from config file and
+ command line */
+ set_args_separator(&res[my_args.size() + 1]);
+ }
+
+ if (*argc)
+ memcpy((uchar*) (res + 1 + my_args.size() + args_sep),
+ (char*) ((*argv)+1),
+ (*argc-1)*sizeof(char*));
+ res[my_args.size() + *argc + args_sep]= 0; /* last null */
+
+ (*argc)+= my_args.size() + args_sep;
+ *argv= res;
+ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
+
+ if (default_directories)
+ *default_directories= dirs;
+
+ if (found_no_defaults)
+ DBUG_RETURN(0);
+
+ if (found_print_defaults)
+ {
+ int i;
+ printf("%s would have been started with the following arguments:\n",
+ **argv);
+ for (i=1 ; i < *argc ; i++)
+ if (!my_getopt_is_args_separator((*argv)[i])) /* skip arguments separator */
+ {
+ if(strncmp((*argv)[i], "--password", 10) == 0)
+ printf("%s ", "--password=*****");
+ else
+ printf("%s ", (*argv)[i]);
+ }
+ puts("");
+ exit(0);
+ }
+
+ DBUG_RETURN(0);
+
+ err:
+ my_message_local(ERROR_LEVEL,
+ "Fatal error in defaults handling. Program aborted!");
+ exit(1);
+ return 0; /* Keep compiler happy */
+}
+
+
+void free_defaults(char **argv)
+{
+ MEM_ROOT ptr;
+ memcpy(&ptr, ((char *) argv) - sizeof(ptr), sizeof(ptr));
+ free_root(&ptr,MYF(0));
+}
+
+
+static int search_default_file(Process_option_func opt_handler,
+ void *handler_ctx,
+ const char *dir,
+ const char *config_file,
+ my_bool is_login_file)
+{
+ char **ext;
+ const char *empty_list[]= { "", 0 };
+ my_bool have_ext= fn_ext(config_file)[0] != 0;
+ const char **exts_to_use= have_ext ? empty_list : f_extensions;
+
+ for (ext= (char**) exts_to_use; *ext; ext++)
+ {
+ int error;
+ if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
+ dir, *ext,
+ config_file, 0, is_login_file)) < 0)
+ return error;
+ }
+ return 0;
+}
+
+
+/*
+ Skip over keyword and get argument after keyword
+
+ SYNOPSIS
+ get_argument()
+ keyword Include directive keyword
+ kwlen Length of keyword
+ ptr Pointer to the keword in the line under process
+ line line number
+
+ RETURN
+ 0 error
+ # Returns pointer to the argument after the keyword.
+*/
+
+static char *get_argument(const char *keyword, size_t kwlen,
+ char *ptr, char *name, uint line)
+{
+ char *end;
+
+ /* Skip over "include / includedir keyword" and following whitespace */
+
+ for (ptr+= kwlen - 1;
+ my_isspace(&my_charset_latin1, ptr[0]);
+ ptr++)
+ {}
+
+ /*
+ Trim trailing whitespace from directory name
+ The -1 below is for the newline added by fgets()
+ Note that my_isspace() is true for \r and \n
+ */
+ for (end= ptr + strlen(ptr) - 1;
+ my_isspace(&my_charset_latin1, *(end - 1));
+ end--)
+ {}
+ end[0]= 0; /* Cut off end space */
+
+ /* Print error msg if there is nothing after !include* directive */
+ if (end <= ptr)
+ {
+ my_message_local(ERROR_LEVEL,
+ "Wrong '!%s' directive in config file %s at line %d!",
+ keyword, name, line);
+ return 0;
+ }
+ return ptr;
+}
+
+
+/*
+ Open a configuration file (if exists) and read given options from it
+
+ SYNOPSIS
+ search_default_file_with_ext()
+ opt_handler Option handler function. It is used to process
+ every separate option.
+ handler_ctx Pointer to the structure to store actual
+ parameters of the function.
+ dir directory to read
+ ext Extension for configuration file
+ config_file Name of configuration file
+ group groups to read
+ recursion_level the level of recursion, got while processing
+ "!include" or "!includedir"
+ is_login_file TRUE, when login file is being processed.
+
+ RETURN
+ 0 Success
+ -1 Fatal error, abort
+ 1 File not found (Warning)
+*/
+
+static int search_default_file_with_ext(Process_option_func opt_handler,
+ void *handler_ctx,
+ const char *dir,
+ const char *ext,
+ const char *config_file,
+ int recursion_level,
+ my_bool is_login_file)
+{
+ char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
+ char *value, option[4096+2], tmp[FN_REFLEN];
+ static const char includedir_keyword[]= "includedir";
+ static const char include_keyword[]= "include";
+ const int max_recursion_level= 10;
+ MYSQL_FILE *fp;
+ uint line=0;
+ my_bool found_group=0;
+ uint i, rc;
+ MY_DIR *search_dir;
+ FILEINFO *search_file;
+
+ if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
+ return 0; /* Ignore wrong paths */
+ if (dir)
+ {
+ end=convert_dirname(name, dir, NullS);
+ if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
+ *end++='.';
+ strxmov(end,config_file,ext,NullS);
+ }
+ else
+ {
+ my_stpcpy(name,config_file);
+ }
+ fn_format(name,name,"","",4);
+
+ if ((rc= check_file_permissions(name, is_login_file)) < 2)
+ return (int) rc;
+
+ if (is_login_file)
+ {
+ if ( !(fp = mysql_file_fopen(key_file_cnf, name, (O_RDONLY | O_BINARY),
+ MYF(0))))
+ return 1; /* Ignore wrong files. */
+ }
+ else
+ {
+ if ( !(fp = mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
+ return 1; /* Ignore wrong files */
+ }
+
+ while (mysql_file_getline(buff, sizeof(buff) - 1, fp, is_login_file))
+ {
+ line++;
+ /* Ignore comment and empty lines */
+ for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
+ {}
+
+ if (*ptr == '#' || *ptr == ';' || !*ptr)
+ continue;
+
+ /* Configuration File Directives */
+ if (*ptr == '!')
+ {
+ if (recursion_level >= max_recursion_level)
+ {
+ for (end= ptr + strlen(ptr) - 1;
+ my_isspace(&my_charset_latin1, *(end - 1));
+ end--)
+ {}
+ end[0]= 0;
+ my_message_local(WARNING_LEVEL,
+ "skipping '%s' directive as maximum include"
+ "recursion level was reached in file %s at line %d!",
+ ptr, name, line);
+ continue;
+ }
+
+ /* skip over `!' and following whitespace */
+ for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
+ {}
+
+ if ((!strncmp(ptr, includedir_keyword,
+ sizeof(includedir_keyword) - 1)) &&
+ my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1]))
+ {
+ if (!(ptr= get_argument(includedir_keyword,
+ sizeof(includedir_keyword),
+ ptr, name, line)))
+ goto err;
+
+ if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
+ goto err;
+
+ for (i= 0; i < search_dir->number_off_files; i++)
+ {
+ search_file= search_dir->dir_entry + i;
+ ext= fn_ext(search_file->name);
+
+ /* check extension */
+ for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
+ {
+ if (!strcmp(ext, *tmp_ext))
+ break;
+ }
+
+ if (*tmp_ext)
+ {
+ fn_format(tmp, search_file->name, ptr, "",
+ MY_UNPACK_FILENAME | MY_SAFE_PATH);
+
+ search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
+ recursion_level + 1, is_login_file);
+ }
+ }
+
+ my_dirend(search_dir);
+ }
+ else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
+ my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1]))
+ {
+ if (!(ptr= get_argument(include_keyword,
+ sizeof(include_keyword), ptr,
+ name, line)))
+ goto err;
+
+ search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
+ recursion_level + 1, is_login_file);
+ }
+
+ continue;
+ }
+
+ if (*ptr == '[') /* Group name */
+ {
+ found_group=1;
+ if (!(end= strchr(++ptr,']')))
+ {
+ my_message_local(ERROR_LEVEL,
+ "Wrong group definition in config file %s at line %d!",
+ name,line);
+ goto err;
+ }
+ /* Remove end space */
+ for ( ; my_isspace(&my_charset_latin1, end[-1]); end --)
+ {}
+
+ end[0]=0;
+
+ strmake(curr_gr, ptr, MY_MIN((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
+
+ /* signal that a new group is found */
+ opt_handler(handler_ctx, curr_gr, NULL);
+
+ continue;
+ }
+ if (!found_group)
+ {
+ my_message_local(ERROR_LEVEL,
+ "Found option without preceding group in config file"
+ " %s at line %d!", name,line);
+ goto err;
+ }
+
+
+ end= remove_end_comment(ptr);
+ if ((value= strchr(ptr, '=')))
+ end= value; /* Option without argument */
+ for ( ; my_isspace(&my_charset_latin1, end[-1]) ; end--)
+ {}
+
+ if (!value)
+ {
+ strmake(my_stpcpy(option,"--"),ptr, (size_t) (end-ptr));
+ if (opt_handler(handler_ctx, curr_gr, option))
+ goto err;
+ }
+ else
+ {
+ /* Remove pre- and end space */
+ char *value_end;
+ for (value++ ; my_isspace(&my_charset_latin1, *value); value ++)
+ {}
+
+ value_end=strend(value);
+ /*
+ We don't have to test for value_end >= value as we know there is
+ an '=' before
+ */
+ for ( ; my_isspace(&my_charset_latin1, value_end[-1]); value_end --)
+ {}
+
+ if (value_end < value) /* Empty string */
+ value_end=value;
+
+ /* remove quotes around argument */
+ if ((*value == '\"' || *value == '\'') && /* First char is quote */
+ (value + 1 < value_end ) && /* String is longer than 1 */
+ *value == value_end[-1] ) /* First char is equal to last char */
+ {
+ value++;
+ value_end--;
+ }
+ ptr=my_stpnmov(my_stpcpy(option,"--"),ptr,(size_t) (end-ptr));
+ *ptr++= '=';
+
+ for ( ; value != value_end; value++)
+ {
+ if (*value == '\\' && value != value_end-1)
+ {
+ switch(*++value) {
+ case 'n':
+ *ptr++='\n';
+ break;
+ case 't':
+ *ptr++= '\t';
+ break;
+ case 'r':
+ *ptr++ = '\r';
+ break;
+ case 'b':
+ *ptr++ = '\b';
+ break;
+ case 's':
+ *ptr++= ' '; /* space */
+ break;
+ case '\"':
+ *ptr++= '\"';
+ break;
+ case '\'':
+ *ptr++= '\'';
+ break;
+ case '\\':
+ *ptr++= '\\';
+ break;
+ default: /* Unknown; Keep '\' */
+ *ptr++= '\\';
+ *ptr++= *value;
+ break;
+ }
+ }
+ else
+ *ptr++= *value;
+ }
+ *ptr=0;
+ if (opt_handler(handler_ctx, curr_gr, option))
+ goto err;
+ }
+ }
+ mysql_file_fclose(fp, MYF(0));
+ return(0);
+
+ err:
+ mysql_file_fclose(fp, MYF(0));
+ return -1; /* Fatal error */
+}
+
+
+static char *remove_end_comment(char *ptr)
+{
+ char quote= 0; /* we are inside quote marks */
+ char escape= 0; /* symbol is protected by escape chagacter */
+
+ for (; *ptr; ptr++)
+ {
+ if ((*ptr == '\'' || *ptr == '\"') && !escape)
+ {
+ if (!quote)
+ quote= *ptr;
+ else if (quote == *ptr)
+ quote= 0;
+ }
+ /* We are not inside a string */
+ if (!quote && *ptr == '#')
+ {
+ *ptr= 0;
+ return ptr;
+ }
+ escape= (quote && *ptr == '\\' && !escape);
+ }
+ return ptr;
+}
+
+
+/**
+ Read one line from the specified file. In case
+ of scrambled login file, the line read is first
+ decrypted and then returned.
+
+ @param str [out] Buffer to store the read text.
+ @param size [in] At max, size-1 bytes to be read.
+ @param file [in] Source file.
+ @param is_login_file [in] TRUE, when login file is being processed.
+
+ @return 1 Success
+ 0 Error
+*/
+
+static my_bool mysql_file_getline(char *str, int size, MYSQL_FILE *file,
+ my_bool is_login_file)
+{
+ uchar cipher[4096], len_buf[MAX_CIPHER_STORE_LEN];
+ static unsigned char my_key[LOGIN_KEY_LEN];
+ int length= 0, cipher_len= 0;
+
+ if (is_login_file)
+ {
+ if (mysql_file_ftell(file, MYF(MY_WME)) == 0)
+ {
+ /* Move past unused bytes. */
+ mysql_file_fseek(file, 4, SEEK_SET, MYF(MY_WME));
+ if (mysql_file_fread(file, my_key, LOGIN_KEY_LEN,
+ MYF(MY_WME)) != LOGIN_KEY_LEN)
+ return 0;
+ }
+
+ if (mysql_file_fread(file, len_buf, MAX_CIPHER_STORE_LEN,
+ MYF(MY_WME)) == MAX_CIPHER_STORE_LEN)
+ {
+ cipher_len= sint4korr(len_buf);
+ if (cipher_len > size)
+ return 0;
+ }
+ else
+ return 0;
+
+ mysql_file_fread(file, cipher, cipher_len, MYF(MY_WME));
+ if ((length= my_aes_decrypt(cipher, cipher_len, (unsigned char *) str,
+ my_key, LOGIN_KEY_LEN, my_aes_128_ecb, NULL)) < 0)
+ {
+ /* Attempt to decrypt failed. */
+ return 0;
+ }
+ str[length]= 0;
+ return 1;
+ }
+ else
+ {
+ if (mysql_file_fgets(str, size, file))
+ return 1;
+ else
+ return 0;
+ }
+}
+
+
+void my_print_default_files(const char *conf_file)
+{
+ const char *empty_list[]= { "", 0 };
+ my_bool have_ext= fn_ext(conf_file)[0] != 0;
+ const char **exts_to_use= have_ext ? empty_list : f_extensions;
+ char name[FN_REFLEN], **ext;
+
+ puts("\nDefault options are read from the following files in the given order:");
+
+ if (dirname_length(conf_file))
+ fputs(conf_file,stdout);
+ else
+ {
+ const char **dirs;
+ MEM_ROOT alloc;
+ init_alloc_root(key_memory_defaults, &alloc, 512, 0);
+
+ if ((dirs= init_default_directories(&alloc)) == NULL)
+ {
+ fputs("Internal error initializing default directories list", stdout);
+ }
+ else
+ {
+ for ( ; *dirs; dirs++)
+ {
+ for (ext= (char**) exts_to_use; *ext; ext++)
+ {
+ const char *pos;
+ char *end;
+ if (**dirs)
+ pos= *dirs;
+ else if (my_defaults_extra_file)
+ pos= my_defaults_extra_file;
+ else
+ continue;
+ end= convert_dirname(name, pos, NullS);
+ if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
+ *end++= '.';
+
+ if (my_defaults_extra_file == pos)
+ end[(strlen(end)-1)] = ' ';
+ else
+ strxmov(end, conf_file, *ext , " ", NullS);
+ fputs(name, stdout);
+ }
+ }
+ }
+
+ free_root(&alloc, MYF(0));
+ }
+ puts("");
+}
+
+void print_defaults(const char *conf_file, const char **groups)
+{
+ const char **groups_save= groups;
+ my_print_default_files(conf_file);
+
+ fputs("The following groups are read:",stdout);
+ for ( ; *groups ; groups++)
+ {
+ fputc(' ',stdout);
+ fputs(*groups,stdout);
+ }
+
+ if (my_defaults_group_suffix)
+ {
+ groups= groups_save;
+ for ( ; *groups ; groups++)
+ {
+ fputc(' ',stdout);
+ fputs(*groups,stdout);
+ fputs(my_defaults_group_suffix,stdout);
+ }
+ }
+ puts("\nThe following options may be given as the first argument:\n\
+--print-defaults Print the program argument list and exit.\n\
+--no-defaults Don't read default options from any option file,\n\
+ except for login file.\n\
+--defaults-file=# Only read default options from the given file #.\n\
+--defaults-extra-file=# Read this file after the global files are read.\n\
+--defaults-group-suffix=#\n\
+ Also read groups with concat(group, suffix)\n\
+--login-path=# Read this path from the login file.");
+}
+
+
+static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
+{
+ char buf[FN_REFLEN];
+ size_t len;
+ char *p;
+ my_bool err MY_ATTRIBUTE((unused));
+
+ len= normalize_dirname(buf, dir);
+ if (!(p= strmake_root(alloc, buf, len)))
+ return 1; /* Failure */
+ /* Should never fail if DEFAULT_DIRS_SIZE is correct size */
+ err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
+ DBUG_ASSERT(err == FALSE);
+
+ return 0;
+}
+
+
+#ifdef _WIN32
+/*
+ This wrapper for GetSystemWindowsDirectory() will dynamically bind to the
+ function if it is available, emulate it on NT4 Terminal Server by stripping
+ the \SYSTEM32 from the end of the results of GetSystemDirectory(), or just
+ return GetSystemDirectory().
+ */
+
+typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT);
+
+static size_t my_get_system_windows_directory(char *buffer, size_t size)
+{
+ size_t count;
+ GET_SYSTEM_WINDOWS_DIRECTORY
+ func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY)
+ GetProcAddress(GetModuleHandle("kernel32.dll"),
+ "GetSystemWindowsDirectoryA");
+
+ if (func_ptr)
+ return func_ptr(buffer, (uint) size);
+
+ /*
+ Windows NT 4.0 Terminal Server Edition:
+ To retrieve the shared Windows directory, call GetSystemDirectory and
+ trim the "System32" element from the end of the returned path.
+ */
+ count= GetSystemDirectory(buffer, (uint) size);
+ if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0)
+ {
+ count-= 8;
+ buffer[count] = '\0';
+ }
+ return count;
+}
+
+
+static const char *my_get_module_parent(char *buf, size_t size)
+{
+ char *last= NULL;
+ char *end;
+ if (!GetModuleFileName(NULL, buf, (DWORD) size))
+ return NULL;
+ end= strend(buf);
+
+ /*
+ Look for the second-to-last \ in the filename, but hang on
+ to a pointer after the last \ in case we're in the root of
+ a drive.
+ */
+ for ( ; end > buf; end--)
+ {
+ if (*end == FN_LIBCHAR)
+ {
+ if (last)
+ {
+ /* Keep the last '\' as this works both with D:\ and a directory */
+ end[1]= 0;
+ break;
+ }
+ last= end;
+ }
+ }
+
+ return buf;
+}
+#endif /* _WIN32 */
+
+
+static const char **init_default_directories(MEM_ROOT *alloc)
+{
+ const char **dirs;
+ char *env;
+ int errors= 0;
+
+ dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
+ if (dirs == NULL)
+ return NULL;
+ memset(dirs, 0, DEFAULT_DIRS_SIZE * sizeof(char *));
+
+#ifdef _WIN32
+
+ {
+ char fname_buffer[FN_REFLEN];
+ if (my_get_system_windows_directory(fname_buffer, sizeof(fname_buffer)))
+ errors += add_directory(alloc, fname_buffer, dirs);
+
+ if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
+ errors += add_directory(alloc, fname_buffer, dirs);
+
+ errors += add_directory(alloc, "C:/", dirs);
+
+ if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
+ errors += add_directory(alloc, fname_buffer, dirs);
+ }
+
+#else
+
+ errors += add_directory(alloc, "/etc/", dirs);
+ errors += add_directory(alloc, "/etc/mysql/", dirs);
+
+#if defined(DEFAULT_SYSCONFDIR)
+ if (DEFAULT_SYSCONFDIR[0])
+ errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
+#endif /* DEFAULT_SYSCONFDIR */
+
+#endif
+
+ if ((env= getenv("MYSQL_HOME")))
+ errors += add_directory(alloc, env, dirs);
+
+ /* Placeholder for --defaults-extra-file=<path> */
+ errors += add_directory(alloc, "", dirs);
+
+#if !defined(_WIN32)
+ errors += add_directory(alloc, "~/", dirs);
+#endif
+
+ return (errors > 0 ? NULL : dirs);
+}
+
+/**
+ Place the login file name in the specified buffer.
+
+ @param file_name [out] Buffer to hold login file name
+ @param file_name_size [in] Length of the buffer
+
+ @return 1 - Success
+ 0 - Failure
+*/
+
+int my_default_get_login_file(char *file_name, size_t file_name_size)
+{
+ size_t rc;
+
+ if (getenv("MYSQL_TEST_LOGIN_FILE"))
+ rc= my_snprintf(file_name, file_name_size, "%s",
+ getenv("MYSQL_TEST_LOGIN_FILE"));
+#ifdef _WIN32
+ else if (getenv("APPDATA"))
+ rc= my_snprintf(file_name, file_name_size, "%s\\MySQL\\.mylogin.cnf",
+ getenv("APPDATA"));
+#else
+ else if (getenv("HOME"))
+ rc= my_snprintf(file_name, file_name_size, "%s/.mylogin.cnf",
+ getenv("HOME"));
+#endif
+ else
+ {
+ memset(file_name, 0, file_name_size);
+ return 0;
+ }
+ /* Anything <= 0 will be treated as error. */
+ if (rc <= 0)
+ return 0;
+
+ return 1;
+}
+
+/**
+ Check file permissions of the option file.
+
+ @param file_name [in] Name of the option file.
+ @param is_login_file [in] TRUE, when login file is being processed.
+
+ @return 0 - Non-allowable file permissions.
+ 1 - Failed to stat.
+ 2 - Success.
+*/
+int check_file_permissions(const char *file_name, my_bool is_login_file)
+{
+#if !defined(_WIN32)
+ MY_STAT stat_info;
+
+ if (!my_stat(file_name,&stat_info,MYF(0)))
+ return 1;
+ /*
+ Ignore .mylogin.cnf file if not exclusively readable/writable
+ by current user.
+ */
+ if (is_login_file && (stat_info.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO))
+ && (stat_info.st_mode & S_IFMT) == S_IFREG)
+ {
+ my_message_local(WARNING_LEVEL, "%s should be readable/writable only by "
+ "current user.", file_name);
+ return 0;
+ }
+ /*
+ Ignore world-writable regular files.
+ This is mainly done to protect us to not read a file created by
+ the mysqld server, but the check is still valid in most context.
+ */
+ else if ((stat_info.st_mode & S_IWOTH) &&
+ (stat_info.st_mode & S_IFMT) == S_IFREG)
+
+ {
+ my_message_local(WARNING_LEVEL,
+ "World-writable config file '%s' is ignored.", file_name);
+ return 0;
+ }
+#endif
+ return 2; /* Success */
+}
+
diff --git a/mysql/mysys_ssl/my_default_priv.h b/mysql/mysys_ssl/my_default_priv.h
new file mode 100644
index 0000000..9c55d47
--- /dev/null
+++ b/mysql/mysys_ssl/my_default_priv.h
@@ -0,0 +1,43 @@
+/* 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef MY_DEFAULT_PRIV_INCLUDED
+#define MY_DEFAULT_PRIV_INCLUDED
+
+#include "my_global.h" /* C_MODE_START, C_MODE_END */
+
+/*
+ Number of byte used to store the length of
+ cipher that follows.
+*/
+#define MAX_CIPHER_STORE_LEN 4U
+#define LOGIN_KEY_LEN 20U
+
+C_MODE_START
+
+/**
+ Place the login file name in the specified buffer.
+
+ @param file_name [out] Buffer to hold login file name
+ @param file_name_size [in] Length of the buffer
+
+ @return 1 - Success
+ 0 - Failure
+*/
+int my_default_get_login_file(char *file_name, size_t file_name_size);
+
+C_MODE_END
+
+#endif /* MY_DEFAULT_PRIV_INCLUDED */
diff --git a/mysql/mysys_ssl/my_getopt.cpp b/mysql/mysys_ssl/my_getopt.cpp
new file mode 100644
index 0000000..40ae171
--- /dev/null
+++ b/mysql/mysys_ssl/my_getopt.cpp
@@ -0,0 +1,1615 @@
+/* Copyright (c) 2002, 2016, 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <m_string.h>
+#include <stdlib.h>
+#include <mysys_err.h>
+#include <my_getopt.h>
+#include <errno.h>
+#include <m_string.h>
+#include "my_default.h"
+#include <m_ctype.h>
+#include "../mysys/mysys_priv.h"
+
+typedef void (*init_func_p)(const struct my_option *option, void *variable,
+ longlong value);
+
+my_error_reporter my_getopt_error_reporter= &my_message_local;
+
+static bool findopt(char *, uint, const struct my_option **);
+my_bool getopt_compare_strings(const char *, const char *, uint);
+static longlong getopt_ll(char *arg, const struct my_option *optp, int *err);
+static ulonglong getopt_ull(char *, const struct my_option *, int *);
+static double getopt_double(char *arg, const struct my_option *optp, int *err);
+static void init_variables(const struct my_option *, init_func_p);
+static void init_one_value(const struct my_option *, void *, longlong);
+static void fini_one_value(const struct my_option *, void *, longlong);
+static int setval(const struct my_option *, void *, char *, my_bool);
+static char *check_struct_option(char *cur_arg, char *key_name);
+static my_bool get_bool_argument(const struct my_option *opts,
+ const char *argument,
+ bool *error);
+
+/*
+ The following three variables belong to same group and the number and
+ order of their arguments must correspond to each other.
+*/
+static const char *special_opt_prefix[]=
+{"skip", "disable", "enable", "maximum", "loose", 0};
+static const uint special_opt_prefix_lengths[]=
+{ 4, 7, 6, 7, 5, 0};
+enum enum_special_opt
+{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE};
+
+char *disabled_my_option= (char*) "0";
+char *enabled_my_option= (char*) "1";
+
+/*
+ This is a flag that can be set in client programs. 0 means that
+ my_getopt will not print error messages, but the client should do
+ it by itself
+*/
+
+my_bool my_getopt_print_errors= 1;
+
+/*
+ This is a flag that can be set in client programs. 1 means that
+ my_getopt will skip over options it does not know how to handle.
+*/
+
+my_bool my_getopt_skip_unknown= 0;
+
+static my_getopt_value getopt_get_addr;
+
+void my_getopt_register_get_addr(my_getopt_value func_addr)
+{
+ getopt_get_addr= func_addr;
+}
+
+
+/**
+ Wrapper around my_handle_options() for interface compatibility.
+
+ @param argc [in, out] Command line options (count)
+ @param argv [in, out] Command line options (values)
+ @param longopts [in] Descriptor of all valid options
+ @param get_one_option [in] Optional callback function to process each option,
+ can be NULL.
+
+ @return Error in case of ambiguous or unknown options,
+ 0 on success.
+*/
+int handle_options(int *argc, char ***argv,
+ const struct my_option *longopts,
+ my_get_one_option get_one_option)
+{
+ return my_handle_options(argc, argv, longopts, get_one_option, NULL, FALSE);
+}
+
+union ull_dbl
+{
+ ulonglong ull;
+ double dbl;
+};
+
+/**
+ Returns an ulonglong value containing a raw
+ representation of the given double value.
+*/
+ulonglong getopt_double2ulonglong(double v)
+{
+ union ull_dbl u;
+ u.dbl= v;
+ compile_time_assert(sizeof(ulonglong) >= sizeof(double));
+ return u.ull;
+}
+
+/**
+ Returns the double value which corresponds to
+ the given raw representation.
+*/
+double getopt_ulonglong2double(ulonglong v)
+{
+ union ull_dbl u;
+ u.ull= v;
+ return u.dbl;
+}
+
+/**
+ Handle command line options.
+ Sort options.
+ Put options first, until special end of options (--),
+ or until the end of argv. Parse options, check that the given option
+ matches with one of the options in struct 'my_option'.
+ Check that option was given an argument if it requires one
+ Call the optional 'get_one_option()' function once for each option.
+
+ Note that handle_options() can be invoked multiple times to
+ parse a command line in several steps.
+ In this case, use the global flag @c my_getopt_skip_unknown to indicate
+ that options unknown in the current step should be preserved in the
+ command line for later parsing in subsequent steps.
+
+ For 'long' options (--a_long_option), @c my_getopt_skip_unknown is
+ fully supported. Command line parameters such as:
+ - "--a_long_option"
+ - "--a_long_option=value"
+ - "--a_long_option value"
+ will be preserved as is when the option is not known.
+
+ For 'short' options (-S), support for @c my_getopt_skip_unknown
+ comes with some limitation, because several short options
+ can also be specified together in the same command line argument,
+ as in "-XYZ".
+
+ The first use case supported is: all short options are declared.
+ handle_options() will be able to interpret "-XYZ" as one of:
+ - an unknown X option
+ - "-X -Y -Z", three short options with no arguments
+ - "-X -YZ", where Y is a short option with argument Z
+ - "-XYZ", where X is a short option with argument YZ
+ based on the full short options specifications.
+
+ The second use case supported is: no short option is declared.
+ handle_options() will reject "-XYZ" as unknown, to be parsed later.
+
+ The use case that is explicitly not supported is to provide
+ only a partial list of short options to handle_options().
+ This function can not be expected to extract some option Y
+ in the middle of the string "-XYZ" in these conditions,
+ without knowing if X will be declared an option later.
+
+ Note that this limitation only impacts parsing of several
+ short options from the same command line argument,
+ as in "mysqld -anW5".
+ When each short option is properly separated out in the command line
+ argument, for example in "mysqld -a -n -w5", the code would actually
+ work even with partial options specs given at each stage.
+
+ @param [in, out] argc command line options (count)
+ @param [in, out] argv command line options (values)
+ @param [in] longopts descriptor of all valid options
+ @param [in] get_one_option optional callback function to process each option,
+ can be NULL.
+ @param [in] command_list NULL-terminated list of strings (commands) which
+ (if set) is looked up for all non-option strings
+ found while parsing the command line parameters.
+ The parsing terminates if a match is found. At
+ exit, argv [out] would contain all the remaining
+ unparsed options along with the matched command.
+
+ @param [in] ignore_unknown_option When set to TRUE, options are continued to
+ be read even when unknown options are
+ encountered.
+
+ @return error in case of ambiguous or unknown options,
+ 0 on success.
+*/
+int my_handle_options(int *argc, char ***argv,
+ const struct my_option *longopts,
+ my_get_one_option get_one_option,
+ const char **command_list, my_bool ignore_unknown_option)
+{
+ uint argvpos= 0, length;
+ my_bool end_of_options= 0, must_be_var, set_maximum_value,
+ option_is_loose;
+ char **pos, **pos_end, *optend, *opt_str, key_name[FN_REFLEN];
+ const struct my_option *optp;
+ void *value;
+ int error, i;
+ my_bool is_cmdline_arg= 1;
+ bool opt_found;
+
+ /* handle_options() assumes arg0 (program name) always exists */
+ DBUG_ASSERT(argc && *argc >= 1);
+ DBUG_ASSERT(argv && *argv);
+ (*argc)--; /* Skip the program name */
+ (*argv)++; /* --- || ---- */
+ init_variables(longopts, init_one_value);
+
+ /*
+ Search for args_separator, if found, then the first part of the
+ arguments are loaded from configs
+ */
+ for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
+ {
+ if (my_getopt_is_args_separator(*pos))
+ {
+ is_cmdline_arg= 0;
+ break;
+ }
+ }
+
+ for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
+ {
+ char **first= pos;
+ char *cur_arg= *pos;
+ opt_found= false;
+ if (!is_cmdline_arg && (my_getopt_is_args_separator(cur_arg)))
+ {
+ is_cmdline_arg= 1;
+
+ /* save the separator too if skip unkown options */
+ if (my_getopt_skip_unknown)
+ (*argv)[argvpos++]= cur_arg;
+ else
+ (*argc)--;
+ continue;
+ }
+ if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
+ {
+ char *argument= 0;
+ must_be_var= 0;
+ set_maximum_value= 0;
+ option_is_loose= 0;
+
+ cur_arg++; /* skip '-' */
+ if (*cur_arg == '-') /* check for long option, */
+ {
+ if (!*++cur_arg) /* skip the double dash */
+ {
+ /* '--' means end of options, look no further */
+ end_of_options= 1;
+ (*argc)--;
+ continue;
+ }
+ opt_str= check_struct_option(cur_arg, key_name);
+ optend= strcend(opt_str, '=');
+ length= (uint) (optend - opt_str);
+ if (*optend == '=')
+ optend++;
+ else
+ optend= 0;
+
+ /*
+ Find first the right option. Return error in case of an ambiguous,
+ or unknown option
+ */
+ optp= longopts;
+ if (!(opt_found= findopt(opt_str, length, &optp)))
+ {
+ /*
+ Didn't find any matching option. Let's see if someone called
+ option with a special option prefix
+ */
+ if (!must_be_var)
+ {
+ if (optend)
+ must_be_var= 1; /* option is followed by an argument */
+ for (i= 0; special_opt_prefix[i]; i++)
+ {
+ if (!getopt_compare_strings(special_opt_prefix[i], opt_str,
+ special_opt_prefix_lengths[i]) &&
+ (opt_str[special_opt_prefix_lengths[i]] == '-' ||
+ opt_str[special_opt_prefix_lengths[i]] == '_'))
+ {
+ /*
+ We were called with a special prefix, we can reuse opt_found
+ */
+ opt_str+= special_opt_prefix_lengths[i] + 1;
+ length-= special_opt_prefix_lengths[i] + 1;
+ if (i == OPT_LOOSE)
+ option_is_loose= 1;
+ if ((opt_found= findopt(opt_str, length, &optp)))
+ {
+ switch (i) {
+ case OPT_SKIP:
+ case OPT_DISABLE: /* fall through */
+ /*
+ double negation is actually enable again,
+ for example: --skip-option=0 -> option = TRUE
+ */
+ optend= (optend && *optend == '0' && !(*(optend + 1))) ?
+ enabled_my_option : disabled_my_option;
+ break;
+ case OPT_ENABLE:
+ optend= (optend && *optend == '0' && !(*(optend + 1))) ?
+ disabled_my_option : enabled_my_option;
+ break;
+ case OPT_MAXIMUM:
+ set_maximum_value= 1;
+ must_be_var= 1;
+ break;
+ }
+ break; /* break from the inner loop, main loop continues */
+ }
+ i= -1; /* restart the loop */
+ }
+ }
+ }
+ if (!opt_found)
+ {
+ if (my_getopt_skip_unknown)
+ {
+ /* Preserve all the components of this unknown option. */
+ do {
+ (*argv)[argvpos++]= *first++;
+ } while (first <= pos);
+ continue;
+ }
+ if (must_be_var)
+ {
+ if (my_getopt_print_errors)
+ my_getopt_error_reporter(option_is_loose ?
+ WARNING_LEVEL : ERROR_LEVEL,
+ "unknown variable '%s'", cur_arg);
+ if (!option_is_loose)
+ return EXIT_UNKNOWN_VARIABLE;
+ }
+ else
+ {
+ if (my_getopt_print_errors)
+ my_getopt_error_reporter(option_is_loose ?
+ WARNING_LEVEL : ERROR_LEVEL,
+ "unknown option '--%s'", cur_arg);
+ if (!(option_is_loose || ignore_unknown_option))
+ return EXIT_UNKNOWN_OPTION;
+ }
+ if (option_is_loose || ignore_unknown_option)
+ {
+ (*argc)--;
+ continue;
+ }
+ }
+ }
+ if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
+ {
+ if (my_getopt_print_errors)
+ my_message_local(option_is_loose ? WARNING_LEVEL : ERROR_LEVEL,
+ "%s: Option '%s' used, but is disabled",
+ my_progname, opt_str);
+ if (option_is_loose)
+ {
+ (*argc)--;
+ continue;
+ }
+ return EXIT_OPTION_DISABLED;
+ }
+ error= 0;
+ value= optp->var_type & GET_ASK_ADDR ?
+ (*getopt_get_addr)(key_name, strlen(key_name), optp, &error) :
+ optp->value;
+ if (error)
+ return error;
+
+ if (optp->arg_type == NO_ARG)
+ {
+ /*
+ Due to historical reasons GET_BOOL var_types still accepts arguments
+ despite the NO_ARG arg_type attribute. This can seems a bit unintuitive
+ and care should be taken when refactoring this code.
+ */
+ if (optend && (optp->var_type & GET_TYPE_MASK) != GET_BOOL)
+ {
+ if (my_getopt_print_errors)
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: option '--%s' cannot take an argument",
+ my_progname, optp->name);
+ return EXIT_NO_ARGUMENT_ALLOWED;
+ }
+ if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
+ {
+ /*
+ Set bool to 1 if no argument or if the user has used
+ --enable-'option-name'.
+ *optend was set to '0' if one used --disable-option
+ */
+ (*argc)--;
+ if(!optend)
+ *((my_bool*) value)= (my_bool) 1;
+ else
+ {
+ my_bool ret= 0;
+ bool error= 0;
+ ret= get_bool_argument(optp, optend, &error);
+ if(error)
+ {
+ my_getopt_error_reporter(WARNING_LEVEL,
+ "%s: ignoring option '--%s' "
+ "due to invalid value '%s'",
+ my_progname, optp->name, optend);
+ continue;
+ }
+ else
+ *((my_bool*) value)= ret;
+ }
+ if (get_one_option && get_one_option(optp->id, optp,
+ *((my_bool*) value) ?
+ enabled_my_option : disabled_my_option))
+ return EXIT_ARGUMENT_INVALID;
+ continue;
+ }
+ argument= optend;
+ }
+ else if (optp->arg_type == REQUIRED_ARG && !optend)
+ {
+ /* Check if there are more arguments after this one,
+ Note: options loaded from config file that requires value
+ should always be in the form '--option=value'.
+ */
+ if (!is_cmdline_arg || !*++pos)
+ {
+ if (my_getopt_print_errors)
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: option '--%s' requires an argument",
+ my_progname, optp->name);
+ return EXIT_ARGUMENT_REQUIRED;
+ }
+ argument= *pos;
+ (*argc)--;
+ }
+ else
+ argument= optend;
+
+ if (optp->var_type == GET_PASSWORD && is_cmdline_arg && argument)
+ print_cmdline_password_warning();
+ }
+ else /* must be short option */
+ {
+ for (optend= cur_arg; *optend; optend++)
+ {
+ opt_found= false;
+ for (optp= longopts; optp->name; optp++)
+ {
+ if (optp->id && optp->id == (int) (uchar) *optend)
+ {
+ /* Option recognized. Find next what to do with it */
+ opt_found= true;
+ if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
+ {
+ if (my_getopt_print_errors)
+ my_message_local(ERROR_LEVEL,
+ "%s: Option '-%c' used, but is disabled",
+ my_progname, optp->id);
+ return EXIT_OPTION_DISABLED;
+ }
+ if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL &&
+ optp->arg_type == NO_ARG)
+ {
+ *((my_bool*) optp->value)= (my_bool) 1;
+ if (get_one_option && get_one_option(optp->id, optp, argument))
+ return EXIT_UNSPECIFIED_ERROR;
+ continue;
+ }
+ else if (optp->arg_type == REQUIRED_ARG ||
+ optp->arg_type == OPT_ARG)
+ {
+ if (*(optend + 1))
+ {
+ /* The rest of the option is option argument */
+ argument= optend + 1;
+ /* This is in effect a jump out of the outer loop */
+ optend= (char*) " ";
+ if (optp->var_type == GET_PASSWORD && is_cmdline_arg)
+ print_cmdline_password_warning();
+ }
+ else
+ {
+ if (optp->arg_type == OPT_ARG)
+ {
+ if (optp->var_type == GET_BOOL)
+ *((my_bool*) optp->value)= (my_bool) 1;
+ if (get_one_option && get_one_option(optp->id, optp, argument))
+ return EXIT_UNSPECIFIED_ERROR;
+ continue;
+ }
+ /* Check if there are more arguments after this one */
+ if (!pos[1])
+ {
+ if (my_getopt_print_errors)
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: option '-%c' requires an argument",
+ my_progname, optp->id);
+ return EXIT_ARGUMENT_REQUIRED;
+ }
+ argument= *++pos;
+ (*argc)--;
+ /* the other loop will break, because *optend + 1 == 0 */
+ }
+ }
+ if ((error= setval(optp, optp->value, argument,
+ set_maximum_value)))
+ return error;
+ if (get_one_option && get_one_option(optp->id, optp, argument))
+ return EXIT_UNSPECIFIED_ERROR;
+ break;
+ }
+ }
+ if (!opt_found)
+ {
+ if (my_getopt_skip_unknown)
+ {
+ /*
+ We are currently parsing a single argv[] argument
+ of the form "-XYZ".
+ One or the argument found (say Y) is not an option.
+ Hack the string "-XYZ" to make a "-YZ" substring in it,
+ and push that to the output as an unrecognized parameter.
+ */
+ DBUG_ASSERT(optend > *pos);
+ DBUG_ASSERT(optend >= cur_arg);
+ DBUG_ASSERT(optend <= *pos + strlen(*pos));
+ DBUG_ASSERT(*optend);
+ optend--;
+ optend[0]= '-'; /* replace 'X' or '-' by '-' */
+ (*argv)[argvpos++]= optend;
+ /*
+ Do not continue to parse at the current "-XYZ" argument,
+ skip to the next argv[] argument instead.
+ */
+ optend= (char*) " ";
+ }
+ else
+ {
+ if (my_getopt_print_errors)
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: unknown option '-%c'",
+ my_progname, *optend);
+ return EXIT_UNKNOWN_OPTION;
+ }
+ }
+ }
+ if (opt_found)
+ (*argc)--; /* option handled (short), decrease argument count */
+ continue;
+ }
+ if ((error= setval(optp, value, argument, set_maximum_value)))
+ return error;
+ if (get_one_option && get_one_option(optp->id, optp, argument))
+ return EXIT_UNSPECIFIED_ERROR;
+
+ (*argc)--; /* option handled (long), decrease argument count */
+ }
+ else /* non-option found */
+ {
+ if (command_list)
+ {
+ while (* command_list)
+ {
+ if (!strcmp(*command_list, cur_arg))
+ {
+ /* Match found. */
+ (*argv)[argvpos ++]= cur_arg;
+
+ /* Copy rest of the un-parsed elements & return. */
+ while ((++ pos) != pos_end)
+ (*argv)[argvpos ++]= *pos;
+ goto done;
+ }
+ command_list ++;
+ }
+ }
+ (*argv)[argvpos ++]= cur_arg;
+ }
+ }
+
+done:
+ /*
+ Destroy the first, already handled option, so that programs that look
+ for arguments in 'argv', without checking 'argc', know when to stop.
+ Items in argv, before the destroyed one, are all non-option -arguments
+ to the program, yet to be (possibly) handled.
+ */
+ (*argv)[argvpos]= 0;
+ return 0;
+}
+
+
+/**
+ * This function should be called to print a warning message
+ * if password string is specified on the command line.
+ */
+
+void print_cmdline_password_warning()
+{
+ static my_bool password_warning_announced= FALSE;
+
+ if (!password_warning_announced)
+ {
+ my_message_local(WARNING_LEVEL, "Using a password on the command line "
+ "interface can be insecure.");
+ password_warning_announced= TRUE;
+ }
+}
+
+
+/**
+ @brief Check for struct options
+
+ @param[in] cur_arg Current argument under processing from argv
+ @param[in] key_name variable where to store the possible key name
+
+ @details
+ In case option is a struct option, returns a pointer to the current
+ argument at the position where the struct option (key_name) ends, the
+ next character after the dot. In case argument is not a struct option,
+ returns a pointer to the argument.
+ key_name will hold the name of the key, or 0 if not found.
+
+ @return char*
+ If struct option Pointer to next character after dot.
+ If no struct option Pointer to the argument
+*/
+
+static char *check_struct_option(char *cur_arg, char *key_name)
+{
+ char *dot_pos, *equal_pos, *space_pos;
+
+ dot_pos= strcend(cur_arg + 1, '.'); /* Skip the first character */
+ equal_pos= strcend(cur_arg, '=');
+ space_pos= strcend(cur_arg, ' ');
+
+ /*
+ If the first dot is after an equal sign, then it is part
+ of a variable value and the option is not a struct option.
+ Also, if the last character in the string before the ending
+ NULL, or the character right before equal sign is the first
+ dot found, the option is not a struct option.
+ */
+ if ((equal_pos > dot_pos) && (space_pos > dot_pos))
+ {
+ size_t len= (uint) (dot_pos - cur_arg);
+ set_if_smaller(len, FN_REFLEN-1);
+ strmake(key_name, cur_arg, len);
+ return ++dot_pos;
+ }
+ else
+ {
+ key_name[0]= 0;
+ return cur_arg;
+ }
+}
+
+
+/**
+ Parse a boolean command line argument
+
+ "ON", "TRUE" and "1" will return true,
+ other values will return false.
+
+ @param[in] argument The value argument
+ @return boolean value
+*/
+static my_bool get_bool_argument(const struct my_option *opts,
+ const char *argument,
+ bool *error)
+{
+ if (!my_strcasecmp(&my_charset_latin1, argument, "true") ||
+ !my_strcasecmp(&my_charset_latin1, argument, "on") ||
+ !my_strcasecmp(&my_charset_latin1, argument, "1"))
+ return 1;
+ else if (!my_strcasecmp(&my_charset_latin1, argument, "false") ||
+ !my_strcasecmp(&my_charset_latin1, argument, "off") ||
+ !my_strcasecmp(&my_charset_latin1, argument, "0"))
+ return 0;
+ else
+ *error= 1;
+ return 0;
+}
+
+/*
+ function: setval
+
+ Arguments: opts, argument
+ Will set the option value to given value
+*/
+
+static int setval(const struct my_option *opts, void *value, char *argument,
+ my_bool set_maximum_value)
+{
+ int err= 0, res= 0;
+ bool error= 0;
+ ulong var_type= opts->var_type & GET_TYPE_MASK;
+
+ if (!argument)
+ argument= enabled_my_option;
+
+ /*
+ Thus check applies only to options that have a defined value
+ storage pointer.
+ We do it for numeric types only, as empty value is a valid
+ option for strings (the only way to reset back to default value).
+ Note: it does not relate to OPT_ARG/REQUIRED_ARG/NO_ARG, since
+ --param="" is not generally the same as --param.
+ TODO: Add an option definition flag to signify whether empty value
+ (i.e. --param="") is an acceptable value or an error and extend
+ the check to all options.
+ */
+ if (!*argument &&
+ (
+ var_type == GET_INT ||
+ var_type == GET_UINT ||
+ var_type == GET_LONG ||
+ var_type == GET_ULONG ||
+ var_type == GET_LL ||
+ var_type == GET_ULL ||
+ var_type == GET_DOUBLE ||
+ var_type == GET_ENUM
+ )
+ )
+ {
+ if (strncmp(opts->name, "port", 10) == 0)
+ {
+ my_getopt_error_reporter(WARNING_LEVEL,
+ "%s: Empty value for '%s' specified. Will throw an error in future versions",
+ my_progname, opts->name);
+ }
+ else
+ {
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: Empty value for '%s' specified",
+ my_progname, opts->name);
+ return EXIT_ARGUMENT_REQUIRED;
+ }
+ }
+
+ if (value)
+ {
+ if (set_maximum_value && !(value= opts->u_max_value))
+ {
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: Maximum value of '%s' cannot be set",
+ my_progname, opts->name);
+ return EXIT_NO_PTR_TO_VARIABLE;
+ }
+
+ switch (var_type) {
+ case GET_BOOL: /* If argument differs from 0, enable option, else disable */
+ *((my_bool*) value)= get_bool_argument(opts, argument, &error);
+ if(error)
+ my_getopt_error_reporter(WARNING_LEVEL,
+ "option '%s': boolean value '%s' wasn't recognized. Set to OFF.",
+ opts->name, argument);
+ break;
+ case GET_INT:
+ *((int*) value)= (int) getopt_ll(argument, opts, &err);
+ break;
+ case GET_UINT:
+ *((uint*) value)= (uint) getopt_ull(argument, opts, &err);
+ break;
+ case GET_LONG:
+ *((long*) value)= (long) getopt_ll(argument, opts, &err);
+ break;
+ case GET_ULONG:
+ *((long*) value)= (long) getopt_ull(argument, opts, &err);
+ break;
+ case GET_LL:
+ *((longlong*) value)= getopt_ll(argument, opts, &err);
+ break;
+ case GET_ULL:
+ *((ulonglong*) value)= getopt_ull(argument, opts, &err);
+ break;
+ case GET_DOUBLE:
+ *((double*) value)= getopt_double(argument, opts, &err);
+ break;
+ case GET_STR:
+ case GET_PASSWORD:
+ if (argument == enabled_my_option)
+ break; /* string options don't use this default of "1" */
+ *((char**) value)= argument;
+ break;
+ case GET_STR_ALLOC:
+ if (argument == enabled_my_option)
+ break; /* string options don't use this default of "1" */
+ my_free(*((char**) value));
+ if (!(*((char**) value)= my_strdup(key_memory_defaults,
+ argument, MYF(MY_WME))))
+ {
+ res= EXIT_OUT_OF_MEMORY;
+ goto ret;
+ };
+ break;
+ case GET_ENUM:
+ {
+ int type= find_type(argument, opts->typelib, FIND_TYPE_BASIC);
+ if (type == 0)
+ {
+ /*
+ Accept an integer representation of the enumerated item.
+ */
+ char *endptr;
+ ulong arg= strtoul(argument, &endptr, 10);
+ if (*endptr || arg >= opts->typelib->count)
+ {
+ res= EXIT_ARGUMENT_INVALID;
+ goto ret;
+ }
+ *(ulong*)value= arg;
+ }
+ else if (type < 0)
+ {
+ res= EXIT_AMBIGUOUS_OPTION;
+ goto ret;
+ }
+ else
+ *(ulong*)value= type - 1;
+ }
+ break;
+ case GET_SET:
+ *((ulonglong*)value)= find_typeset(argument, opts->typelib, &err);
+ if (err)
+ {
+ /* Accept an integer representation of the set */
+ char *endptr;
+ ulonglong arg= (ulonglong) strtol(argument, &endptr, 10);
+ if (*endptr || (arg >> 1) >= (1ULL << (opts->typelib->count-1)))
+ {
+ res= EXIT_ARGUMENT_INVALID;
+ goto ret;
+ };
+ *(ulonglong*)value= arg;
+ err= 0;
+ }
+ break;
+ case GET_FLAGSET:
+ {
+ char *error;
+ uint error_len;
+
+ *((ulonglong*)value)=
+ find_set_from_flags(opts->typelib, opts->typelib->count,
+ *(ulonglong *)value, opts->def_value,
+ argument, (uint)strlen(argument),
+ &error, &error_len);
+ if (error)
+ {
+ res= EXIT_ARGUMENT_INVALID;
+ goto ret;
+ };
+ }
+ break;
+ case GET_NO_ARG: /* get_one_option has taken care of the value already */
+ default: /* dummy default to avoid compiler warnings */
+ break;
+ }
+ if (err)
+ {
+ res= EXIT_UNKNOWN_SUFFIX;
+ goto ret;
+ };
+ }
+ return 0;
+
+ret:
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: Error while setting value '%s' to '%s'",
+ my_progname, argument, opts->name);
+ return res;
+}
+
+
+/**
+ Find option
+
+ IMPLEMENTATION
+ Go through all options in the my_option struct. Return true
+ if an option is found. sets opt_res to the option found, if any.
+
+ @param optpat name of option to find (with - or _)
+ @param length Length of optpat
+ @param[in,out] opt_res Options
+
+ @retval false No matching options
+ @retval true Found an option
+*/
+
+static bool findopt(char *optpat, uint length,
+ const struct my_option **opt_res)
+{
+ for (const struct my_option *opt= *opt_res; opt->name; opt++)
+ if (!getopt_compare_strings(opt->name, optpat, length) &&
+ !opt->name[length])
+ {
+ (*opt_res)= opt;
+ return true;
+ }
+ return false;
+}
+
+
+/*
+ function: compare_strings
+
+ Works like strncmp, other than 1.) considers '-' and '_' the same.
+ 2.) Returns -1 if strings differ, 0 if they are equal
+*/
+
+my_bool getopt_compare_strings(const char *s, const char *t,
+ uint length)
+{
+ char const *end= s + length;
+ for (;s != end ; s++, t++)
+ {
+ if ((*s != '-' ? *s : '_') != (*t != '-' ? *t : '_'))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ function: eval_num_suffix
+
+ Transforms a number with a suffix to real number. Suffix can
+ be k|K for kilo, m|M for mega or g|G for giga.
+*/
+
+static longlong eval_num_suffix(char *argument, int *error, char *option_name)
+{
+ char *endchar;
+ longlong num;
+
+ *error= 0;
+ errno= 0;
+ num= my_strtoll(argument, &endchar, 10);
+ if (errno == ERANGE)
+ {
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "Incorrect integer value: '%s'", argument);
+ *error= 1;
+ return 0;
+ }
+ if (*endchar == 'k' || *endchar == 'K')
+ num*= 1024L;
+ else if (*endchar == 'm' || *endchar == 'M')
+ num*= 1024L * 1024L;
+ else if (*endchar == 'g' || *endchar == 'G')
+ num*= 1024L * 1024L * 1024L;
+ else if (*endchar)
+ {
+ my_message_local(ERROR_LEVEL,
+ "Unknown suffix '%c' used for variable '%s' (value '%s')",
+ *endchar, option_name, argument);
+ *error= 1;
+ return 0;
+ }
+ return num;
+}
+
+/**
+ function: eval_num_suffix_ull
+ This is the same as eval_num_suffix, but is meant for unsigned long long
+ values. Transforms an unsigned number with a suffix to real number. Suffix can
+ be k|K for kilo, m|M for mega or g|G for giga.
+ @param [IN] argument argument value for option_name
+ @param [IN, OUT] error error no.
+ @param [IN] option_name name of option
+*/
+
+static ulonglong eval_num_suffix_ull(char *argument, int *error, char *option_name)
+{
+ char *endchar;
+ ulonglong num;
+
+ *error= 0;
+ errno= 0;
+ num= my_strtoull(argument, &endchar, 10);
+ if (errno == ERANGE)
+ {
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "Incorrect unsigned integer value: '%s'", argument);
+ *error= 1;
+ return 0;
+ }
+ if (*endchar == 'k' || *endchar == 'K')
+ num*= 1024L;
+ else if (*endchar == 'm' || *endchar == 'M')
+ num*= 1024L * 1024L;
+ else if (*endchar == 'g' || *endchar == 'G')
+ num*= 1024L * 1024L * 1024L;
+ else if (*endchar)
+ {
+ my_message_local(ERROR_LEVEL,
+ "Unknown suffix '%c' used for variable '%s' (value '%s')",
+ *endchar, option_name, argument);
+ *error= 1;
+ return 0;
+ }
+ return num;
+}
+
+/*
+ function: getopt_ll
+
+ Evaluates and returns the value that user gave as an argument
+ to a variable. Recognizes (case insensitive) K as KILO, M as MEGA
+ and G as GIGA bytes. Some values must be in certain blocks, as
+ defined in the given my_option struct, this function will check
+ that those values are honored.
+ In case of an error, set error value in *err.
+*/
+
+static longlong getopt_ll(char *arg, const struct my_option *optp, int *err)
+{
+ longlong num=eval_num_suffix(arg, err, (char*) optp->name);
+ return getopt_ll_limit_value(num, optp, NULL);
+}
+
+
+/**
+ Maximum possible value for an integer GET_* variable type
+ @param var_type type of integer variable (GET_*)
+ @returns maximum possible value for this type
+ */
+ulonglong max_of_int_range(int var_type)
+{
+ switch (var_type)
+ {
+ case GET_INT:
+ return INT_MAX;
+ case GET_LONG:
+ return LONG_MAX;
+ case GET_LL:
+ return LLONG_MAX;
+ case GET_UINT:
+ return UINT_MAX;
+ case GET_ULONG:
+ return ULONG_MAX;
+ case GET_ULL:
+ return ULLONG_MAX;
+ default:
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
+
+/*
+ function: getopt_ll_limit_value
+
+ Applies min/max/block_size to a numeric value of an option.
+ Returns "fixed" value.
+*/
+
+longlong getopt_ll_limit_value(longlong num, const struct my_option *optp,
+ my_bool *fix)
+{
+ longlong old= num;
+ my_bool adjusted= FALSE;
+ char buf1[255], buf2[255];
+ ulonglong block_size= (optp->block_size ? (ulonglong) optp->block_size : 1L);
+ const longlong max_of_type=
+ (longlong)max_of_int_range(optp->var_type & GET_TYPE_MASK);
+
+ if (num > 0 && ((ulonglong) num > (ulonglong) optp->max_value) &&
+ optp->max_value) /* if max value is not set -> no upper limit */
+ {
+ num= (ulonglong) optp->max_value;
+ adjusted= TRUE;
+ }
+
+ if (num > max_of_type)
+ {
+ num= max_of_type;
+ adjusted= TRUE;
+ }
+
+ num= (num / block_size);
+ num= (longlong) (num * block_size);
+
+ if (num < optp->min_value)
+ {
+ num= optp->min_value;
+ if (old < optp->min_value)
+ adjusted= TRUE;
+ }
+
+ if (fix)
+ *fix= old != num;
+ else if (adjusted)
+ my_getopt_error_reporter(WARNING_LEVEL,
+ "option '%s': signed value %s adjusted to %s",
+ optp->name, llstr(old, buf1), llstr(num, buf2));
+ return num;
+}
+
+static inline my_bool is_negative_num(char* num)
+{
+ while (my_isspace(&my_charset_latin1, *num))
+ num++;
+
+ return (*num == '-');
+}
+
+/*
+ function: getopt_ull
+
+ This is the same as getopt_ll, but is meant for unsigned long long
+ values.
+*/
+
+static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err)
+{
+ char buf[255];
+ ulonglong num;
+
+ /* If a negative number is specified as a value for the option. */
+ if (arg == NULL || is_negative_num(arg) == TRUE)
+ {
+ num= (ulonglong) optp->min_value;
+ my_getopt_error_reporter(WARNING_LEVEL,
+ "option '%s': value %s adjusted to %s",
+ optp->name, arg, ullstr(num, buf));
+ }
+ else
+ num= eval_num_suffix_ull(arg, err, (char*) optp->name);
+
+ return getopt_ull_limit_value(num, optp, NULL);
+}
+
+
+ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp,
+ my_bool *fix)
+{
+ my_bool adjusted= FALSE;
+ ulonglong old= num;
+ char buf1[255], buf2[255];
+ const ulonglong max_of_type=
+ max_of_int_range(optp->var_type & GET_TYPE_MASK);
+
+ if (num > (ulonglong) optp->max_value &&
+ optp->max_value) /* if max value is not set -> no upper limit */
+ {
+ num= (ulonglong) optp->max_value;
+ adjusted= TRUE;
+ }
+
+ if (num > max_of_type)
+ {
+ num= max_of_type;
+ adjusted= TRUE;
+ }
+
+ if (optp->block_size > 1)
+ {
+ num/= (ulonglong) optp->block_size;
+ num*= (ulonglong) optp->block_size;
+ }
+
+ if (num < (ulonglong) optp->min_value)
+ {
+ num= (ulonglong) optp->min_value;
+ if (old < (ulonglong) optp->min_value)
+ adjusted= TRUE;
+ }
+
+ if (fix)
+ *fix= old != num;
+ else if (adjusted)
+ my_getopt_error_reporter(WARNING_LEVEL,
+ "option '%s': unsigned value %s adjusted to %s",
+ optp->name, ullstr(old, buf1), ullstr(num, buf2));
+
+ return num;
+}
+
+double getopt_double_limit_value(double num, const struct my_option *optp,
+ my_bool *fix)
+{
+ my_bool adjusted= FALSE;
+ double old= num;
+ double min, max;
+
+ max= getopt_ulonglong2double(optp->max_value);
+ min= getopt_ulonglong2double(optp->min_value);
+ if (max && num > max)
+ {
+ num= max;
+ adjusted= TRUE;
+ }
+ if (num < min)
+ {
+ num= min;
+ adjusted= TRUE;
+ }
+ if (fix)
+ *fix= adjusted;
+ else if (adjusted)
+ my_getopt_error_reporter(WARNING_LEVEL,
+ "option '%s': value %g adjusted to %g",
+ optp->name, old, num);
+ return num;
+}
+
+/*
+ Get double value withing ranges
+
+ Evaluates and returns the value that user gave as an argument to a variable.
+
+ RETURN
+ decimal value of arg
+
+ In case of an error, prints an error message and sets *err to
+ EXIT_ARGUMENT_INVALID. Otherwise err is not touched
+*/
+
+static double getopt_double(char *arg, const struct my_option *optp, int *err)
+{
+ double num;
+ int error;
+ char *end= arg + 1000; /* Big enough as *arg is \0 terminated */
+ num= my_strtod(arg, &end, &error);
+ if (end[0] != 0 || error)
+ {
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "Invalid decimal value for option '%s'\n", optp->name);
+ *err= EXIT_ARGUMENT_INVALID;
+ return 0.0;
+ }
+ return getopt_double_limit_value(num, optp, NULL);
+}
+
+/*
+ Init one value to it's default values
+
+ SYNOPSIS
+ init_one_value()
+ option Option to initialize
+ value Pointer to variable
+*/
+
+static void init_one_value(const struct my_option *option, void *variable,
+ longlong value)
+{
+ DBUG_ENTER("init_one_value");
+ switch ((option->var_type & GET_TYPE_MASK)) {
+ case GET_BOOL:
+ *((my_bool*) variable)= (my_bool) value;
+ break;
+ case GET_INT:
+ *((int*) variable)= (int) getopt_ll_limit_value((int) value, option, NULL);
+ break;
+ case GET_ENUM:
+ *((ulong*) variable)= (ulong) value;
+ break;
+ case GET_UINT:
+ *((uint*) variable)= (uint) getopt_ull_limit_value((uint) value, option, NULL);
+ break;
+ case GET_LONG:
+ *((long*) variable)= (long) getopt_ll_limit_value((long) value, option, NULL);
+ break;
+ case GET_ULONG:
+ *((ulong*) variable)= (ulong) getopt_ull_limit_value((ulong) value, option, NULL);
+ break;
+ case GET_LL:
+ *((longlong*) variable)= getopt_ll_limit_value(value, option, NULL);
+ break;
+ case GET_ULL:
+ *((ulonglong*) variable)= getopt_ull_limit_value((ulonglong) value, option, NULL);
+ break;
+ case GET_SET:
+ case GET_FLAGSET:
+ *((ulonglong*) variable)= (ulonglong) value;
+ break;
+ case GET_DOUBLE:
+ *((double*) variable)= getopt_ulonglong2double(value);
+ break;
+ case GET_STR:
+ case GET_PASSWORD:
+ /*
+ Do not clear variable value if it has no default value.
+ The default value may already be set.
+ NOTE: To avoid compiler warnings, we first cast longlong to intptr,
+ so that the value has the same size as a pointer.
+ */
+ if ((char*) (intptr) value)
+ *((char**) variable)= (char*) (intptr) value;
+ break;
+ case GET_STR_ALLOC:
+ /*
+ Do not clear variable value if it has no default value.
+ The default value may already be set.
+ NOTE: To avoid compiler warnings, we first cast longlong to intptr,
+ so that the value has the same size as a pointer.
+ */
+ if ((char*) (intptr) value)
+ {
+ char **pstr= (char **) variable;
+ my_free(*pstr);
+ *pstr= my_strdup(key_memory_defaults,
+ (char*) (intptr) value, MYF(MY_WME));
+ }
+ break;
+ default: /* dummy default to avoid compiler warnings */
+ break;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Init one value to it's default values
+
+ SYNOPSIS
+ init_one_value()
+ option Option to initialize
+ value Pointer to variable
+*/
+
+static void fini_one_value(const struct my_option *option, void *variable,
+ longlong value MY_ATTRIBUTE ((unused)))
+{
+ DBUG_ENTER("fini_one_value");
+ switch ((option->var_type & GET_TYPE_MASK)) {
+ case GET_STR_ALLOC:
+ my_free(*((char**) variable));
+ *((char**) variable)= NULL;
+ break;
+ default: /* dummy default to avoid compiler warnings */
+ break;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void my_cleanup_options(const struct my_option *options)
+{
+ init_variables(options, fini_one_value);
+}
+
+
+/*
+ initialize all variables to their default values
+
+ SYNOPSIS
+ init_variables()
+ options Array of options
+
+ NOTES
+ We will initialize the value that is pointed to by options->value.
+ If the value is of type GET_ASK_ADDR, we will ask for the address
+ for a value and initialize.
+*/
+
+static void init_variables(const struct my_option *options,
+ init_func_p init_one_value)
+{
+ DBUG_ENTER("init_variables");
+ for (; options->name; options++)
+ {
+ void *value;
+ DBUG_PRINT("options", ("name: '%s'", options->name));
+ /*
+ We must set u_max_value first as for some variables
+ options->u_max_value == options->value and in this case we want to
+ set the value to default value.
+ */
+ if (options->u_max_value)
+ init_one_value(options, options->u_max_value, options->max_value);
+ value= (options->var_type & GET_ASK_ADDR ?
+ (*getopt_get_addr)("", 0, options, 0) : options->value);
+ if (value)
+ init_one_value(options, value, options->def_value);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/**
+ Prints variable or option name, replacing _ with - to given file stream
+ parameter (by default to stdout).
+ @param [IN] optp my_option parameter
+ @param [IN] file stream where the output of optp parameter name
+ goes (by default to stdout).
+*/
+static uint print_name(const struct my_option *optp, FILE* file = stdout)
+{
+ const char *s= optp->name;
+ for (;*s;s++)
+ putc(*s == '_' ? '-' : *s, file);
+ return s - optp->name;
+}
+
+/*
+ function: my_print_options
+
+ Print help for all options and variables.
+*/
+
+void my_print_help(const struct my_option *options)
+{
+ uint col, name_space= 22, comment_space= 57;
+ const char *line_end;
+ const struct my_option *optp;
+
+ for (optp= options; optp->name; optp++)
+ {
+ if (optp->id && optp->id < 256)
+ {
+ printf(" -%c%s", optp->id, strlen(optp->name) ? ", " : " ");
+ col= 6;
+ }
+ else
+ {
+ printf(" ");
+ col= 2;
+ }
+ if (strlen(optp->name))
+ {
+ printf("--");
+ col+= 2 + print_name(optp);
+ if (optp->arg_type == NO_ARG ||
+ (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
+ {
+ putchar(' ');
+ col++;
+ }
+ else if ((optp->var_type & GET_TYPE_MASK) == GET_STR ||
+ (optp->var_type & GET_TYPE_MASK) == GET_PASSWORD ||
+ (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC ||
+ (optp->var_type & GET_TYPE_MASK) == GET_ENUM ||
+ (optp->var_type & GET_TYPE_MASK) == GET_SET ||
+ (optp->var_type & GET_TYPE_MASK) == GET_FLAGSET )
+ {
+ printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "",
+ optp->arg_type == OPT_ARG ? "]" : "");
+ col+= (optp->arg_type == OPT_ARG) ? 8 : 6;
+ }
+ else
+ {
+ printf("%s=#%s ", optp->arg_type == OPT_ARG ? "[" : "",
+ optp->arg_type == OPT_ARG ? "]" : "");
+ col+= (optp->arg_type == OPT_ARG) ? 5 : 3;
+ }
+ if (col > name_space && optp->comment && *optp->comment)
+ {
+ putchar('\n');
+ col= 0;
+ }
+ }
+ for (; col < name_space; col++)
+ putchar(' ');
+ if (optp->comment && *optp->comment)
+ {
+ const char *comment= optp->comment, *end= strend(comment);
+
+ while ((uint) (end - comment) > comment_space)
+ {
+ for (line_end= comment + comment_space; *line_end != ' '; line_end--)
+ {}
+ for (; comment != line_end; comment++)
+ putchar(*comment);
+ comment++; /* skip the space, as a newline will take it's place now */
+ putchar('\n');
+ for (col= 0; col < name_space; col++)
+ putchar(' ');
+ }
+ printf("%s", comment);
+ }
+ putchar('\n');
+ if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
+ {
+ if (optp->def_value != 0)
+ {
+ printf("%*s(Defaults to on; use --skip-", name_space, "");
+ print_name(optp);
+ printf(" to disable.)\n");
+ }
+ }
+ }
+}
+
+/**
+ function: my_print_variables
+ Print variables.
+ @param [IN] options my_option list
+*/
+void my_print_variables(const struct my_option *options)
+{
+ my_print_variables_ex(options, stdout);
+}
+
+/**
+ function: my_print_variables_ex
+ Print variables to given file parameter stream (by default to stdout).
+ @param [IN] options my_options list
+ @param [IN] file stream where the output goes.
+*/
+
+void my_print_variables_ex(const struct my_option *options, FILE* file)
+{
+ uint name_space= 34, nr;
+ size_t length;
+ ulonglong llvalue;
+ char buff[255];
+ const struct my_option *optp;
+
+ for (optp= options; optp->name; optp++)
+ {
+ length= strlen(optp->name)+1;
+ if (length > name_space)
+ name_space= length;
+ }
+
+ fprintf(file, "\nVariables (--variable-name=value)\n");
+ fprintf(file, "%-*s%s", name_space, "and boolean options {FALSE|TRUE}",
+ "Value (after reading options)\n");
+ for (length=1; length < 75; length++)
+ putc(length == name_space ? ' ' : '-', file);
+ putc('\n', file);
+
+ for (optp= options; optp->name; optp++)
+ {
+ void *value= (optp->var_type & GET_ASK_ADDR ?
+ (*getopt_get_addr)("", 0, optp, 0) : optp->value);
+ if (value)
+ {
+ length= print_name(optp, file);
+ for (; length < name_space; length++)
+ putc(' ', file);
+ switch ((optp->var_type & GET_TYPE_MASK)) {
+ case GET_SET:
+ if (!(llvalue= *(ulonglong*) value))
+ fprintf(file, "%s\n", "");
+ else
+ for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1)
+ {
+ if (llvalue & 1)
+ fprintf(file, llvalue > 1 ? "%s," : "%s\n",
+ get_type(optp->typelib, nr));
+ }
+ break;
+ case GET_FLAGSET:
+ llvalue= *(ulonglong*) value;
+ for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1)
+ {
+ fprintf(file, "%s%s=", (nr ? "," : ""), get_type(optp->typelib, nr));
+ fprintf(file, llvalue & 1 ? "on" : "off");
+ }
+ fprintf(file, "\n");
+ break;
+ case GET_ENUM:
+ fprintf(file, "%s\n", get_type(optp->typelib, *(ulong*) value));
+ break;
+ case GET_STR:
+ case GET_PASSWORD:
+ case GET_STR_ALLOC: /* fall through */
+ fprintf(file, "%s\n", *((char**) value) ? *((char**) value) :
+ "(No default value)");
+ break;
+ case GET_BOOL:
+ fprintf(file, "%s\n", *((my_bool*) value) ? "TRUE" : "FALSE");
+ break;
+ case GET_INT:
+ fprintf(file, "%d\n", *((int*) value));
+ break;
+ case GET_UINT:
+ fprintf(file, "%d\n", *((uint*) value));
+ break;
+ case GET_LONG:
+ fprintf(file, "%ld\n", *((long*) value));
+ break;
+ case GET_ULONG:
+ fprintf(file, "%lu\n", *((ulong*) value));
+ break;
+ case GET_LL:
+ fprintf(file, "%s\n", llstr(*((longlong*) value), buff));
+ break;
+ case GET_ULL:
+ longlong2str(*((ulonglong*) value), buff, 10);
+ fprintf(file, "%s\n", buff);
+ break;
+ case GET_DOUBLE:
+ fprintf(file, "%g\n", *(double*) value);
+ break;
+ case GET_NO_ARG:
+ fprintf(file, "(No default value)\n");
+ break;
+ default:
+ fprintf(file, "(Disabled)\n");
+ break;
+ }
+ }
+ }
+}
diff --git a/mysql/mysys_ssl/my_md5.cpp b/mysql/mysys_ssl/my_md5.cpp
new file mode 100644
index 0000000..4c14366
--- /dev/null
+++ b/mysql/mysys_ssl/my_md5.cpp
@@ -0,0 +1,68 @@
+/* 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+
+/**
+ @file
+
+ @brief
+ Wrapper functions for OpenSSL and YaSSL. Also provides a Compatibility layer
+ to make available YaSSL's MD5 implementation.
+*/
+
+#include <my_global.h>
+#include <my_md5.h>
+
+#if defined(HAVE_YASSL)
+#include "my_config.h"
+#include "md5.hpp"
+
+static void my_md5_hash(char *digest, const char *buf, int len)
+{
+ TaoCrypt::MD5 hasher;
+ hasher.Update((TaoCrypt::byte *) buf, len);
+ hasher.Final((TaoCrypt::byte *) digest);
+}
+
+#elif defined(HAVE_OPENSSL)
+#include <openssl/md5.h>
+
+static void my_md5_hash(unsigned char* digest, unsigned const char *buf, int len)
+{
+ MD5_CTX ctx;
+ MD5_Init (&ctx);
+ MD5_Update (&ctx, buf, len);
+ MD5_Final (digest, &ctx);
+}
+
+#endif /* HAVE_YASSL */
+
+/**
+ Wrapper function to compute MD5 message digest.
+
+ @param digest [out] Computed MD5 digest
+ @param buf [in] Message to be computed
+ @param len [in] Length of the message
+
+ @return void
+*/
+void compute_md5_hash(char *digest, const char *buf, int len)
+{
+#if defined(HAVE_YASSL)
+ my_md5_hash(digest, buf, len);
+#elif defined(HAVE_OPENSSL)
+ my_md5_hash((unsigned char*)digest, (unsigned const char*)buf, len);
+#endif /* HAVE_YASSL */
+}
diff --git a/mysql/mysys_ssl/my_murmur3.cpp b/mysql/mysys_ssl/my_murmur3.cpp
new file mode 100644
index 0000000..82dccb6
--- /dev/null
+++ b/mysql/mysys_ssl/my_murmur3.cpp
@@ -0,0 +1,134 @@
+/* Copyright (c) 2013, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
+
+/*
+ Implementation of 32-bit version of MurmurHash3 - fast non-cryptographic
+ hash function with good statistical properties, which is based on public
+ domain code by Austin Appleby.
+*/
+
+#include <my_murmur3.h>
+
+
+/*
+ Platform-specific implementations of ROTL32 helper.
+*/
+
+#if defined(_MSC_VER)
+
+/* Microsoft Visual Studio supports intrinsic for rotate left. */
+
+#include <stdlib.h>
+
+#define ROTL32(x, y) _rotl(x, y)
+
+/*
+ Force inlining of intrinsic even though /Oi option is turned off
+ in release builds.
+*/
+#pragma intrinsic(_rotl)
+
+#else // !defined(_MSC_VER)
+
+/*
+ Many other compilers should be able to optimize the below
+ function to single instruction.
+*/
+
+inline uint32 rotl32 (uint32 x, char r)
+{
+ return (x << r) | (x >> (32 - r));
+}
+
+#define ROTL32(x,y) rotl32(x,y)
+
+#endif // !defined(_MSC_VER)
+
+
+/**
+ Compute 32-bit version of MurmurHash3 hash for the key.
+
+ @param key Key for which hash value to be computed.
+ @param len Key length.
+ @param seed Seed for hash computation.
+
+ @note WARNING! Since MurmurHash3 is known to be susceptible to "hash DoS"
+ attack it should not be used in any situation where attacker has
+ control over key being hashed and thus can cause performance problems
+ due to degradation of hash lookup to linear list search.
+
+ @returns Hash value for the key.
+*/
+
+uint32 murmur3_32(const uchar *key, size_t len, uint32 seed)
+{
+ const uchar *tail= key + (len - len % 4);
+
+ uint32 h1= seed;
+
+ /* Constants for magic numbers that are used more than once. */
+ const uint32 c1= 0xcc9e2d51;
+ const uint32 c2= 0x1b873593;
+
+ /* Body: process all 32-bit blocks in the key. */
+
+ for (const uchar *data= key; data != tail; data+= 4)
+ {
+ uint32 k1= uint4korr(data);
+
+ k1*= c1;
+ k1= ROTL32(k1, 15);
+ k1*= c2;
+
+ h1^= k1;
+ h1= ROTL32(h1, 13);
+ h1= h1 * 5 + 0xe6546b64;
+ }
+
+ /* Tail: handle remaining len % 4 bytes. */
+
+ uint32 k1= 0;
+
+ switch(len % 4)
+ {
+ case 3:
+ k1^= static_cast<uint32>(tail[2]) << 16;
+ /* Fall through. */
+ case 2:
+ k1^= static_cast<uint32>(tail[1]) << 8;
+ /* Fall through. */
+ case 1:
+ k1^= tail[0];
+ k1*= c1;
+ k1= ROTL32(k1, 15);
+ k1*= c2;
+ h1^= k1;
+ };
+
+ /*
+ Finalization mix:
+ Add length and force all bits of a hash block to avalanche.
+ */
+
+ h1^= len;
+
+ h1^= h1 >> 16;
+ h1*= 0x85ebca6b;
+ h1^= h1 >> 13;
+ h1*= 0xc2b2ae35;
+ h1^= h1 >> 16;
+
+ return h1;
+}
diff --git a/mysql/mysys_ssl/my_rnd.cpp b/mysql/mysys_ssl/my_rnd.cpp
new file mode 100644
index 0000000..19fd37e
--- /dev/null
+++ b/mysql/mysys_ssl/my_rnd.cpp
@@ -0,0 +1,115 @@
+/*
+ Copyright (c) 2012, 2014, 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 02110-1301 USA */
+
+#include <my_rnd.h>
+
+#if defined(HAVE_YASSL)
+
+#if defined(YASSL_PREFIX)
+#define RAND_bytes yaRAND_bytes
+#endif /* YASSL_PREFIX */
+
+#include <openssl/ssl.h>
+
+#elif defined(HAVE_OPENSSL)
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#endif /* HAVE_YASSL */
+
+
+/*
+ A wrapper to use OpenSSL/yaSSL PRNGs.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ Generate random number.
+
+ @param rand_st [INOUT] Structure used for number generation.
+
+ @retval Generated pseudo random number.
+*/
+
+double my_rnd(struct rand_struct *rand_st)
+{
+ rand_st->seed1= (rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+ rand_st->seed2= (rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+ return (((double) rand_st->seed1) / rand_st->max_value_dbl);
+}
+
+
+
+/**
+Fill a buffer with random bytes using the SSL library routines
+
+@param buffer [OUT] Buffer to receive the random data
+@param buffer_size [IN] sizeof the the buffer
+
+@retval 1 error ocurred.
+@retval 0 OK
+*/
+int
+my_rand_buffer(unsigned char *buffer, size_t buffer_size)
+{
+ int rc;
+#if defined(HAVE_YASSL) /* YaSSL */
+ rc= yaSSL::RAND_bytes(buffer, buffer_size);
+
+ if (!rc)
+ return 1;
+#elif defined(HAVE_OPENSSL)
+ rc= RAND_bytes(buffer, buffer_size);
+
+ if (!rc)
+ {
+ ERR_clear_error();
+ return 1;
+ }
+#else /* no SSL */
+#error not using an SSL library not supported
+#endif
+ return 0;
+}
+
+
+/**
+ Generate a random number using the OpenSSL/yaSSL supplied
+ random number generator if available.
+
+ @param rand_st [INOUT] Structure used for number generation
+ only if none of the SSL libraries are
+ available.
+
+ @retval Generated random number.
+*/
+
+double my_rnd_ssl(struct rand_struct *rand_st)
+{
+ unsigned int res;
+
+ if (my_rand_buffer((unsigned char *) &res, sizeof(res)))
+ return my_rnd(rand_st);
+
+ return (double)res / (double)UINT_MAX;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/mysql/mysys_ssl/my_sha1.cpp b/mysql/mysys_ssl/my_sha1.cpp
new file mode 100644
index 0000000..5d9d480
--- /dev/null
+++ b/mysql/mysys_ssl/my_sha1.cpp
@@ -0,0 +1,141 @@
+/* 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+
+/**
+ @file
+
+ @brief
+ Wrapper functions for OpenSSL, YaSSL implementations. Also provides a
+ Compatibility layer to make available YaSSL's SHA1 implementation.
+*/
+
+#include <my_global.h>
+#include <sha1.h>
+
+#if defined(HAVE_YASSL)
+#include "sha.hpp"
+
+/**
+ Compute SHA1 message digest using YaSSL.
+
+ @param digest [out] Computed SHA1 digest
+ @param buf [in] Message to be computed
+ @param len [in] Length of the message
+
+ @return void
+*/
+void mysql_sha1_yassl(uint8 *digest, const char *buf, size_t len)
+{
+ TaoCrypt::SHA hasher;
+ hasher.Update((const TaoCrypt::byte *) buf, (TaoCrypt::word32)len);
+ hasher.Final ((TaoCrypt::byte *) digest);
+}
+
+/**
+ Compute SHA1 message digest for two messages in order to
+ emulate sha1(msg1, msg2) using YaSSL.
+
+ @param digest [out] Computed SHA1 digest
+ @param buf1 [in] First message
+ @param len1 [in] Length of first message
+ @param buf2 [in] Second message
+ @param len2 [in] Length of second message
+
+ @return void
+*/
+void mysql_sha1_multi_yassl(uint8 *digest, const char *buf1, int len1,
+ const char *buf2, int len2)
+{
+ TaoCrypt::SHA hasher;
+ hasher.Update((const TaoCrypt::byte *) buf1, len1);
+ hasher.Update((const TaoCrypt::byte *) buf2, len2);
+ hasher.Final((TaoCrypt::byte *) digest);
+}
+
+#elif defined(HAVE_OPENSSL)
+#include <openssl/sha.h>
+
+int mysql_sha1_reset(SHA_CTX *context)
+{
+ return SHA1_Init(context);
+}
+
+
+int mysql_sha1_input(SHA_CTX *context, const uint8 *message_array,
+ unsigned length)
+{
+ return SHA1_Update(context, message_array, length);
+}
+
+
+int mysql_sha1_result(SHA_CTX *context,
+ uint8 Message_Digest[SHA1_HASH_SIZE])
+{
+ return SHA1_Final(Message_Digest, context);
+}
+
+#endif /* HAVE_YASSL */
+
+/**
+ Wrapper function to compute SHA1 message digest.
+
+ @param digest [out] Computed SHA1 digest
+ @param buf [in] Message to be computed
+ @param len [in] Length of the message
+
+ @return void
+*/
+void compute_sha1_hash(uint8 *digest, const char *buf, size_t len)
+{
+#if defined(HAVE_YASSL)
+ mysql_sha1_yassl(digest, buf, len);
+#elif defined(HAVE_OPENSSL)
+ SHA_CTX sha1_context;
+
+ mysql_sha1_reset(&sha1_context);
+ mysql_sha1_input(&sha1_context, (const uint8 *) buf, len);
+ mysql_sha1_result(&sha1_context, digest);
+#endif /* HAVE_YASSL */
+}
+
+
+/**
+ Wrapper function to compute SHA1 message digest for
+ two messages in order to emulate sha1(msg1, msg2).
+
+ @param digest [out] Computed SHA1 digest
+ @param buf1 [in] First message
+ @param len1 [in] Length of first message
+ @param buf2 [in] Second message
+ @param len2 [in] Length of second message
+
+ @return void
+*/
+void compute_sha1_hash_multi(uint8 *digest, const char *buf1, int len1,
+ const char *buf2, int len2)
+{
+#if defined(HAVE_YASSL)
+ mysql_sha1_multi_yassl(digest, buf1, len1, buf2, len2);
+#elif defined(HAVE_OPENSSL)
+ SHA_CTX sha1_context;
+
+ mysql_sha1_reset(&sha1_context);
+ mysql_sha1_input(&sha1_context, (const uint8 *) buf1, len1);
+ mysql_sha1_input(&sha1_context, (const uint8 *) buf2, len2);
+ mysql_sha1_result(&sha1_context, digest);
+#endif /* HAVE_YASSL */
+}
+
diff --git a/mysql/mysys_ssl/my_sha2.cpp b/mysql/mysys_ssl/my_sha2.cpp
new file mode 100644
index 0000000..0020033
--- /dev/null
+++ b/mysql/mysys_ssl/my_sha2.cpp
@@ -0,0 +1,68 @@
+/* Copyright (c) 2007, 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+
+/**
+ @file
+ A compatibility layer to our built-in SSL implementation, to mimic the
+ oft-used external library, OpenSSL.
+*/
+
+#include <my_global.h>
+#include <sha2.h>
+
+#ifdef HAVE_YASSL
+
+/*
+ If TaoCrypt::SHA512 or ::SHA384 are not defined (but ::SHA256 is), it's
+ probably that neither of config.h's SIZEOF_LONG or SIZEOF_LONG_LONG are
+ 64 bits long. At present, both OpenSSL and YaSSL require 64-bit integers
+ for SHA-512. (The SIZEOF_* definitions come from autoconf's config.h .)
+*/
+
+# define GEN_YASSL_SHA2_BRIDGE(size) \
+unsigned char* SHA##size(const unsigned char *input_ptr, size_t input_length, \
+ char unsigned *output_ptr) { \
+ TaoCrypt::SHA##size hasher; \
+ \
+ hasher.Update(input_ptr, input_length); \
+ hasher.Final(output_ptr); \
+ return(output_ptr); \
+}
+
+
+/**
+ @fn SHA512
+ @fn SHA384
+ @fn SHA256
+ @fn SHA224
+
+ Instantiate an hash object, fill in the cleartext value, compute the digest,
+ and extract the result from the object.
+
+ (Generate the functions. See similar .h code for the prototypes.)
+*/
+# ifndef OPENSSL_NO_SHA512
+GEN_YASSL_SHA2_BRIDGE(512);
+GEN_YASSL_SHA2_BRIDGE(384);
+# else
+# warning Some SHA2 functionality is missing. See OPENSSL_NO_SHA512.
+# endif
+GEN_YASSL_SHA2_BRIDGE(256);
+GEN_YASSL_SHA2_BRIDGE(224);
+
+# undef GEN_YASSL_SHA2_BRIDGE
+
+#endif /* HAVE_YASSL */