1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-22 01:57:14 +02:00

Add MariaDB Connector/C as a built-in alternative (v3.2.3).

This commit is contained in:
Sandu Liviu Catalin
2021-09-21 20:59:01 +03:00
parent f192767853
commit b4bf96ce4b
372 changed files with 90819 additions and 11 deletions

470
vendor/MDBC/libmariadb/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,470 @@
INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/include
${CC_SOURCE_DIR}/libmariadb)
ADD_DEFINITIONS(-D HAVE_COMPRESS)
ADD_DEFINITIONS(-D LIBMARIADB)
ADD_DEFINITIONS(-D THREAD)
INCLUDE(${CC_SOURCE_DIR}/cmake/sign.cmake)
SET(MARIADB_LIB_SYMBOLS
mariadb_cancel
mariadb_connection
mariadb_convert_string
ma_pvio_register_callback
mariadb_get_charset_by_name
mariadb_stmt_execute_direct
mariadb_get_charset_by_nr
mariadb_get_info
mariadb_get_infov
mysql_get_timeout_value
mysql_get_timeout_value_ms
mysql_optionsv
mysql_ps_fetch_functions
mariadb_reconnect
mysql_stmt_warning_count
mariadb_stmt_fetch_fields
mariadb_rpl_open
mariadb_rpl_close
mariadb_rpl_fetch
mariadb_rpl_optionsv
mariadb_rpl_get_optionsv
mariadb_rpl_init_ex
mariadb_free_rpl_event
mariadb_field_attr
)
IF(WITH_SSL)
SET(MARIADB_LIB_SYMBOLS ${MARIADB_LIB_SYMBOLS} mariadb_deinitialize_ssl)
ENDIF()
SET(MYSQL_LIB_SYMBOLS
mysql_affected_rows
mysql_autocommit
mysql_change_user
mysql_character_set_name
mysql_client_find_plugin
mysql_client_register_plugin
mysql_close
mysql_commit
mysql_data_seek
mysql_debug
mysql_dump_debug_info
mysql_embedded
mysql_eof
mysql_errno
mysql_error
mysql_escape_string
mysql_fetch_field
mysql_fetch_field_direct
mysql_fetch_fields
mysql_fetch_lengths
mysql_fetch_row
mysql_field_count
mysql_field_seek
mysql_field_tell
mysql_free_result
mysql_get_character_set_info
mysql_get_charset_by_name
mysql_get_charset_by_nr
mysql_get_client_info
mysql_get_client_version
mysql_get_host_info
mysql_get_option
mysql_get_optionv
mysql_get_parameters
mysql_get_proto_info
mysql_get_server_info
mysql_get_server_name
mysql_get_server_version
mysql_get_socket
mysql_get_ssl_cipher
mysql_hex_string
mysql_info
mysql_init
mysql_insert_id
mysql_kill
mysql_list_dbs
mysql_list_fields
mysql_list_processes
mysql_list_tables
mysql_load_plugin
mysql_load_plugin_v
mysql_more_results
mysql_net_field_length
mysql_net_read_packet
mysql_next_result
mysql_num_fields
mysql_num_rows
mysql_options
mysql_options4
mysql_ping
mysql_query
mysql_read_query_result
mysql_real_connect
mysql_real_escape_string
mysql_real_query
mysql_refresh
mysql_reset_connection
mysql_rollback
mysql_row_seek
mysql_row_tell
mysql_select_db
mysql_send_query
mysql_server_end
mysql_server_init
mysql_session_track_get_next
mysql_session_track_get_first
mysql_set_character_set
mysql_set_local_infile_default
mysql_set_local_infile_handler
mysql_set_server_option
mysql_shutdown
mysql_sqlstate
mysql_ssl_set
mysql_stat
mysql_stmt_affected_rows
mysql_stmt_attr_get
mysql_stmt_attr_set
mysql_stmt_bind_param
mysql_stmt_bind_result
mysql_stmt_close
mysql_stmt_data_seek
mysql_stmt_errno
mysql_stmt_error
mysql_stmt_execute
mysql_stmt_fetch
mysql_stmt_fetch_column
mysql_stmt_field_count
mysql_stmt_free_result
mysql_stmt_init
mysql_stmt_insert_id
mysql_stmt_more_results
mysql_stmt_next_result
mysql_stmt_num_rows
mysql_stmt_param_count
mysql_stmt_param_metadata
mysql_stmt_prepare
mysql_stmt_reset
mysql_stmt_result_metadata
mysql_stmt_row_seek
mysql_stmt_row_tell
mysql_stmt_send_long_data
mysql_stmt_sqlstate
mysql_stmt_store_result
mysql_store_result
mysql_thread_end
mysql_thread_id
mysql_thread_init
mysql_thread_safe
mysql_use_result
mysql_warning_count)
# some gcc versions fail to compile asm parts of my_context.c,
# if build type is "Release" (see CONC-133), so we need to add -g flag
IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_BUILD_TYPE MATCHES "Release")
SET_SOURCE_FILES_PROPERTIES(my_context.c PROPERTIES COMPILE_FLAGS -g)
ENDIF()
SET(MARIADB_DYNCOL_SYMBOLS
mariadb_dyncol_check
mariadb_dyncol_column_cmp_named
mariadb_dyncol_column_count
mariadb_dyncol_create_many_named
mariadb_dyncol_create_many_num
mariadb_dyncol_exists_named
mariadb_dyncol_exists_num
mariadb_dyncol_free
mariadb_dyncol_get_named
mariadb_dyncol_get_num
mariadb_dyncol_has_names
mariadb_dyncol_json
mariadb_dyncol_list_named
mariadb_dyncol_list_num
mariadb_dyncol_unpack
mariadb_dyncol_update_many_named
mariadb_dyncol_update_many_num
mariadb_dyncol_val_double
mariadb_dyncol_val_long
mariadb_dyncol_val_str)
SET(MARIADB_NONBLOCK_SYMBOLS
mysql_autocommit_cont
mysql_autocommit_start
mysql_change_user_cont
mysql_change_user_start
mysql_close_cont
mysql_close_start
mysql_commit_cont
mysql_commit_start
mysql_dump_debug_info_cont
mysql_dump_debug_info_start
mysql_fetch_row_cont
mysql_fetch_row_start
mysql_free_result_cont
mysql_free_result_start
mysql_kill_cont
mysql_kill_start
mysql_list_fields_cont
mysql_list_fields_start
mysql_next_result_cont
mysql_next_result_start
mysql_ping_cont
mysql_ping_start
mysql_reset_connection_start
mysql_reset_connection_cont
mysql_query_cont
mysql_query_start
mysql_read_query_result_cont
mysql_read_query_result_start
mysql_real_connect_cont
mysql_real_connect_start
mysql_real_query_cont
mysql_real_query_start
mysql_refresh_cont
mysql_refresh_start
mysql_rollback_cont
mysql_rollback_start
mysql_select_db_cont
mysql_select_db_start
mysql_send_query_cont
mysql_send_query_start
mysql_set_character_set_cont
mysql_set_character_set_start
mysql_set_server_option_cont
mysql_set_server_option_start
mysql_shutdown_cont
mysql_shutdown_start
mysql_stat_cont
mysql_stat_start
mysql_stmt_close_cont
mysql_stmt_close_start
mysql_stmt_execute_cont
mysql_stmt_execute_start
mysql_stmt_fetch_cont
mysql_stmt_fetch_start
mysql_stmt_free_result_cont
mysql_stmt_free_result_start
mysql_stmt_next_result_cont
mysql_stmt_next_result_start
mysql_stmt_prepare_cont
mysql_stmt_prepare_start
mysql_stmt_reset_cont
mysql_stmt_reset_start
mysql_stmt_send_long_data_cont
mysql_stmt_send_long_data_start
mysql_stmt_store_result_cont
mysql_stmt_store_result_start
mysql_store_result_cont
mysql_store_result_start
)
# handle static plugins
SET(LIBMARIADB_SOURCES ${LIBMARIADB_PLUGIN_SOURCES})
SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBMARIADB_PLUGIN_LIBS} ${INTERNAL_ZLIB_LIBRARY})
ADD_DEFINITIONS(${LIBMARIADB_PLUGIN_DEFS})
FOREACH(plugin ${PLUGINS_STATIC})
SET(EXTERNAL_PLUGINS "${EXTERNAL_PLUGINS} extern struct st_mysql_client_plugin ${plugin}_client_plugin;\n")
SET(BUILTIN_PLUGINS "${BUILTIN_PLUGINS} (struct st_mysql_client_plugin *)&${plugin}_client_plugin,\n")
ENDFOREACH()
CONFIGURE_FILE(${CC_SOURCE_DIR}/libmariadb/ma_client_plugin.c.in
${CC_BINARY_DIR}/libmariadb/ma_client_plugin.c)
SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES}
${CC_SOURCE_DIR}/plugins/auth/my_auth.c
ma_array.c
ma_charset.c
ma_hashtbl.c
ma_net.c
mariadb_charset.c
ma_time.c
ma_default.c
ma_errmsg.c
mariadb_lib.c
ma_list.c
ma_pvio.c
ma_tls.c
ma_alloc.c
ma_compress.c
ma_init.c
ma_password.c
ma_ll2str.c
ma_sha1.c
mariadb_stmt.c
ma_loaddata.c
ma_stmt_codec.c
ma_string.c
ma_dtoa.c
mariadb_rpl.c
${CC_BINARY_DIR}/libmariadb/ma_client_plugin.c
ma_io.c
${SSL_SOURCES}
)
IF(WIN32)
ADD_DEFINITIONS(-DSIZEOF_CHARP=${CMAKE_SIZEOF_VOID_P})
INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/win-iconv)
SET(LIBMARIADB_SOURCES
${LIBMARIADB_SOURCES}
${CC_SOURCE_DIR}/win-iconv/win_iconv.c
win32_errmsg.c
win32_errmsg.h)
ELSE()
IF(ICONV_INCLUDE_DIR)
INCLUDE_DIRECTORIES(BEFORE ${ICONV_INCLUDE_DIR})
ENDIF()
IF(NOT CMAKE_SYSTEM_NAME MATCHES AIX)
ADD_DEFINITIONS(-DLIBICONV_PLUG)
ENDIF()
ENDIF()
IF(ZLIB_FOUND AND WITH_EXTERNAL_ZLIB)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
ELSE()
SET(ZLIB_SOURCES
../zlib/adler32.c
../zlib/compress.c
../zlib/crc32.c
../zlib/deflate.c
../zlib/gzclose.c
../zlib/gzlib.c
../zlib/gzread.c
../zlib/gzwrite.c
../zlib/infback.c
../zlib/inffast.c
../zlib/inflate.c
../zlib/inftrees.c
../zlib/trees.c
../zlib/uncompr.c
../zlib/zutil.c
)
SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES} ${ZLIB_SOURCES})
INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/zlib)
ENDIF()
IF(WITH_DYNCOL)
MESSAGE1(WITH_DYNCOL "Dynamic column API support: ON")
SET(MARIADB_LIB_SYMBOLS ${MARIADB_LIB_SYMBOLS} ${MARIADB_DYNCOL_SYMBOLS})
SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES} mariadb_dyncol.c)
ENDIF()
SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES} mariadb_async.c ma_context.c)
SET(MARIADB_LIB_SYMBOLS ${MARIADB_LIB_SYMBOLS} ${MARIADB_NONBLOCK_SYMBOLS})
INCLUDE(${CC_SOURCE_DIR}/cmake/export.cmake)
IF(NOT WIN32)
CREATE_EXPORT_FILE(WRITE mariadbclient.def
"libmysqlclient_18"
"${MYSQL_LIB_SYMBOLS}"
"libmariadbclient_18")
CREATE_EXPORT_FILE(APPEND mariadbclient.def
"libmariadb_3"
"${MARIADB_LIB_SYMBOLS}"
"")
ELSE()
CREATE_EXPORT_FILE(WRITE mariadbclient.def
"libmariadb_3"
"${MARIADB_LIB_SYMBOLS};${MYSQL_LIB_SYMBOLS}"
"")
ENDIF()
IF(CMAKE_VERSION VERSION_GREATER 2.8.7)
# CREATE OBJECT LIBRARY
ADD_LIBRARY(mariadb_obj OBJECT ${LIBMARIADB_SOURCES})
IF(UNIX)
SET_TARGET_PROPERTIES(mariadb_obj PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}")
ENDIF()
SET (MARIADB_OBJECTS $<TARGET_OBJECTS:mariadb_obj>)
ELSE()
SET (MARIADB_OBJECTS ${LIBMARIADB_SOURCES})
ENDIF()
# Xcode doesn't support targets that have only object files,
# so let's add an empty file to keep Xcode happy
IF(CMAKE_GENERATOR MATCHES Xcode)
FILE(WRITE ${CC_BINARY_DIR}/libmariadb/empty.c "")
SET(EMPTY_FILE ${CC_BINARY_DIR}/libmariadb/empty.c)
ENDIF()
#* create file with list of functions */
FILE(WRITE ${CC_BINARY_DIR}/manpages.list "${MARIADB_LIB_SYMBOLS};${MYSQL_LIB_SYMBOLS}")
IF(WIN32)
SET_VERSION_INFO("TARGET:libmariadb"
"FILE_TYPE:VFT_DLL"
"SOURCE_FILE:libmariadb/libmariadb.c"
"ORIGINAL_FILE_NAME:libmariadb.dll"
"FILE_DESCRIPTION:Dynamic lib for client/server communication")
ENDIF()
ADD_LIBRARY(mariadbclient STATIC ${MARIADB_OBJECTS} ${EMPTY_FILE})
TARGET_LINK_LIBRARIES(mariadbclient ${SYSTEM_LIBS})
IF(UNIX)
ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} ${MARIADB_OBJECTS} ${EMPTY_FILE})
SET_TARGET_PROPERTIES(libmariadb PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}")
ELSE()
ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} ${MARIADB_OBJECTS} mariadbclient.def)
SET_TARGET_PROPERTIES(libmariadb PROPERTIES LINKER_LANGUAGE C)
ENDIF()
TARGET_LINK_LIBRARIES(libmariadb LINK_PRIVATE ${SYSTEM_LIBS})
SIGN_TARGET(libmariadb)
IF(CMAKE_SYSTEM_NAME MATCHES "Linux" OR
CMAKE_SYSTEM_NAME MATCHES "kFreeBSD" OR
CMAKE_SYSTEM_NAME MATCHES "GNU")
IF (NOT WITH_ASAN AND NOT WITH_TSAN AND NOT WITH_UBSAN AND NOT WITH_MSAN)
TARGET_LINK_LIBRARIES (libmariadb LINK_PRIVATE "-Wl,--no-undefined")
ENDIF()
SET_TARGET_PROPERTIES(libmariadb PROPERTIES LINK_FLAGS "${CC_BINARY_DIR}/libmariadb/mariadbclient.def")
ENDIF()
SET_TARGET_PROPERTIES(mariadbclient PROPERTIES IMPORTED_INTERFACE_LINK_LIBRARIES "${SYSTEM_LIBS}")
SET_TARGET_PROPERTIES(libmariadb PROPERTIES IMPORTED_INTERFACE_LINK_LIBRARIES "${SYSTEM_LIBS}")
SET_TARGET_PROPERTIES(libmariadb PROPERTIES PREFIX "")
#
# Installation
#
INCLUDE(${CC_SOURCE_DIR}/cmake/symlink.cmake)
# There are still several projects which don't make use
# of the config program. To make sure these programs can
# use mariadb client library we provide libmysql symlinks
IF(WITH_MYSQLCOMPAT)
create_symlink(libmysqlclient${CMAKE_SHARED_LIBRARY_SUFFIX} libmariadb ${INSTALL_LIBDIR})
create_symlink(libmysqlclient_r${CMAKE_SHARED_LIBRARY_SUFFIX} libmariadb ${INSTALL_LIBDIR})
IF(NOT CMAKE_SYSTEM_NAME MATCHES AIX)
create_symlink(libmysqlclient${CMAKE_STATIC_LIBRARY_SUFFIX} mariadbclient ${INSTALL_LIBDIR})
create_symlink(libmysqlclient_r${CMAKE_STATIC_LIBRARY_SUFFIX} mariadbclient ${INSTALL_LIBDIR})
ENDIF()
ENDIF()
SET_TARGET_PROPERTIES(libmariadb PROPERTIES VERSION
${CPACK_PACKAGE_VERSION_MAJOR}
SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
IF(NOT WIN32)
SET_TARGET_PROPERTIES(mariadbclient PROPERTIES OUTPUT_NAME "${LIBMARIADB_STATIC_NAME}")
ENDIF()
INSTALL(TARGETS mariadbclient
COMPONENT Development
DESTINATION ${INSTALL_LIBDIR})
INSTALL(TARGETS libmariadb
COMPONENT SharedLibraries
DESTINATION ${INSTALL_LIBDIR})
IF(MSVC)
# On Windows, install PDB
INSTALL(FILES $<TARGET_PDB_FILE:libmariadb> DESTINATION "${INSTALL_LIBDIR}"
CONFIGURATIONS Debug RelWithDebInfo
COMPONENT Development)
ENDIF()

33
vendor/MDBC/libmariadb/bmove_upp.c vendored Normal file
View File

@ -0,0 +1,33 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/* File : bmove.c
Author : Michael widenius
Updated: 1987-03-20
Defines: bmove_upp()
bmove_upp(dst, src, len) moves exactly "len" bytes from the source
"src-len" to the destination "dst-len" counting downwards.
*/
#include <ma_global.h>
#include "ma_string.h"
void ma_bmove_upp(register char *dst, register const char *src, register size_t len)
{
while (len-- != 0) *--dst = *--src;
}

172
vendor/MDBC/libmariadb/get_password.c vendored Normal file
View File

@ -0,0 +1,172 @@
/************************************************************************************
Copyright (C) 2014 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include <ma_global.h>
#include <ma_sys.h>
#include "mysql.h"
#include <ma_string.h>
#include <mariadb_ctype.h>
#include <stdio.h>
#include <memory.h>
#ifndef _WIN32
#include <termios.h>
#else
#include <conio.h>
#endif /* _WIN32 */
/* {{{ static char *get_password() */
/*
read password from device
SYNOPSIS
get_password
Hdl/file file handle
buffer input buffer
length buffer length
RETURN
buffer zero terminated input buffer
*/
#ifdef _WIN32
static char *get_password(HANDLE Hdl, char *buffer, DWORD length)
#else
static char *get_password(FILE *file, char *buffer, int length)
#endif
{
char inChar;
int CharsProcessed= 1;
#ifdef _WIN32
DWORD Offset= 0;
#else
int Offset= 0;
#endif
memset(buffer, 0, length);
do
{
#ifdef _WIN32
if (!ReadConsole(Hdl, &inChar, 1, (DWORD *)&CharsProcessed, NULL) ||
!CharsProcessed)
break;
#else
inChar= (char)fgetc(file);
#endif
switch(inChar) {
case '\b': /* backslash */
if (Offset)
{
/* cursor is always at the end */
Offset--;
buffer[Offset]= 0;
#ifdef _WIN32
_cputs("\b \b");
#endif
}
break;
case '\n':
case '\r':
break;
default:
buffer[Offset]= inChar;
if (Offset < length - 2)
Offset++;
#ifdef _WIN32
_cputs("*");
#endif
break;
}
} while (CharsProcessed && inChar != '\n' && inChar != '\r');
return buffer;
}
/* }}} */
/* {{{ static char* get_tty_password */
/*
reads password from tty/console
SYNOPSIS
get_tty_password()
buffer input buffer
length length of input buffer
DESCRIPTION
reads a password from console (Windows) or tty without echoing
it's characters. Input buffer must be allocated by calling function.
RETURNS
buffer pointer to input buffer
*/
char* get_tty_password(char *prompt, char *buffer, int length)
{
#ifdef _WIN32
DWORD SaveState;
HANDLE Hdl;
if (prompt)
fprintf(stderr, "%s", prompt);
if (!(Hdl= CreateFile("CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING, 0, NULL)))
{
/* todo: provide a graphical dialog */
return buffer;
}
/* Save ConsoleMode and set ENABLE_PROCESSED_INPUT:
CTRL+C is processed by the system and is not placed in the input buffer */
GetConsoleMode(Hdl, &SaveState);
SetConsoleMode(Hdl, ENABLE_PROCESSED_INPUT);
buffer= get_password(Hdl, buffer, length);
SetConsoleMode(Hdl, SaveState);
CloseHandle(Hdl);
return buffer;
#else
struct termios term_old,
term_new;
FILE *readfrom;
if (prompt && isatty(fileno(stderr)))
fputs(prompt, stderr);
if (!(readfrom= fopen("/dev/tty", "r")))
readfrom= stdin;
/* try to disable echo */
tcgetattr(fileno(readfrom), &term_old);
term_new= term_old;
term_new.c_cc[VMIN] = 1;
term_new.c_cc[VTIME]= 0;
term_new.c_lflag&= ~(ECHO | ISIG | ICANON | ECHONL);
tcsetattr(fileno(readfrom), TCSADRAIN, &term_new);
buffer= get_password(readfrom, buffer, length);
if (isatty(fileno(readfrom)))
tcsetattr(fileno(readfrom), TCSADRAIN, &term_old);
fclose(readfrom);
return buffer;
#endif
}
/* }}} */

193
vendor/MDBC/libmariadb/ma_alloc.c vendored Normal file
View File

@ -0,0 +1,193 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/* Routines to handle mallocing of results which will be freed the same time */
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_string.h>
void ma_init_alloc_root(MA_MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size)
{
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
mem_root->min_malloc=32;
mem_root->block_size= (block_size-MALLOC_OVERHEAD-sizeof(MA_USED_MEM)+8);
mem_root->error_handler=0;
mem_root->block_num= 4;
mem_root->first_block_usage= 0;
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
if (pre_alloc_size)
{
if ((mem_root->free = mem_root->pre_alloc=
(MA_USED_MEM*) malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(MA_USED_MEM)))))
{
mem_root->free->size=pre_alloc_size+ALIGN_SIZE(sizeof(MA_USED_MEM));
mem_root->free->left=pre_alloc_size;
mem_root->free->next=0;
}
}
#endif
}
void * ma_alloc_root(MA_MEM_ROOT *mem_root, size_t Size)
{
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
reg1 MA_USED_MEM *next;
Size+=ALIGN_SIZE(sizeof(MA_USED_MEM));
if (!(next = (MA_USED_MEM*) malloc(Size)))
{
if (mem_root->error_handler)
(*mem_root->error_handler)();
return((void *) 0); /* purecov: inspected */
}
next->next=mem_root->used;
mem_root->used=next;
return (void *) (((char*) next)+ALIGN_SIZE(sizeof(MA_USED_MEM)));
#else
size_t get_size;
void * point;
reg1 MA_USED_MEM *next= 0;
reg2 MA_USED_MEM **prev;
Size= ALIGN_SIZE(Size);
if ((*(prev= &mem_root->free)))
{
if ((*prev)->left < Size &&
mem_root->first_block_usage++ >= 16 &&
(*prev)->left < 4096)
{
next= *prev;
*prev= next->next;
next->next= mem_root->used;
mem_root->used= next;
mem_root->first_block_usage= 0;
}
for (next= *prev; next && next->left < Size; next= next->next)
prev= &next->next;
}
if (! next)
{ /* Time to alloc new block */
get_size= MAX(Size+ALIGN_SIZE(sizeof(MA_USED_MEM)),
(mem_root->block_size & ~1) * (mem_root->block_num >> 2));
if (!(next = (MA_USED_MEM*) malloc(get_size)))
{
if (mem_root->error_handler)
(*mem_root->error_handler)();
return((void *) 0); /* purecov: inspected */
}
mem_root->block_num++;
next->next= *prev;
next->size= get_size;
next->left= get_size-ALIGN_SIZE(sizeof(MA_USED_MEM));
*prev=next;
}
point= (void *) ((char*) next+ (next->size-next->left));
if ((next->left-= Size) < mem_root->min_malloc)
{ /* Full block */
*prev=next->next; /* Remove block from list */
next->next=mem_root->used;
mem_root->used=next;
mem_root->first_block_usage= 0;
}
return(point);
#endif
}
/* deallocate everything used by alloc_root */
void ma_free_root(MA_MEM_ROOT *root, myf MyFlags)
{
reg1 MA_USED_MEM *next,*old;
if (!root)
return; /* purecov: inspected */
if (!(MyFlags & MY_KEEP_PREALLOC))
root->pre_alloc=0;
for ( next=root->used; next ;)
{
old=next; next= next->next ;
if (old != root->pre_alloc)
free(old);
}
for (next= root->free ; next ; )
{
old=next; next= next->next ;
if (old != root->pre_alloc)
free(old);
}
root->used=root->free=0;
if (root->pre_alloc)
{
root->free=root->pre_alloc;
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(MA_USED_MEM));
root->free->next=0;
}
}
char *ma_strdup_root(MA_MEM_ROOT *root,const char *str)
{
size_t len= strlen(str)+1;
char *pos;
if ((pos=ma_alloc_root(root,len)))
memcpy(pos,str,len);
return pos;
}
char *ma_memdup_root(MA_MEM_ROOT *root, const char *str, size_t len)
{
char *pos;
if ((pos= ma_alloc_root(root,len)))
memcpy(pos,str,len);
return pos;
}
void *ma_multi_malloc(myf myFlags, ...)
{
va_list args;
char **ptr,*start,*res;
size_t tot_length,length;
va_start(args,myFlags);
tot_length=0;
while ((ptr=va_arg(args, char **)))
{
length=va_arg(args, size_t);
tot_length+=ALIGN_SIZE(length);
}
va_end(args);
if (!(start=(char *)malloc(tot_length)))
return 0;
va_start(args,myFlags);
res=start;
while ((ptr=va_arg(args, char **)))
{
*ptr=res;
length=va_arg(args,size_t);
res+=ALIGN_SIZE(length);
}
va_end(args);
return start;
}

172
vendor/MDBC/libmariadb/ma_array.c vendored Normal file
View File

@ -0,0 +1,172 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/* Handling of arrays that can grow dynamically. */
#undef SAFEMALLOC /* Problems with threads */
#include <ma_global.h>
#include <ma_sys.h>
#include "ma_string.h"
#include <memory.h>
/*
Initiate array and alloc space for init_alloc elements. Array is usable
even if space allocation failed
*/
my_bool ma_init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
uint init_alloc, uint alloc_increment CALLER_INFO_PROTO)
{
if (!alloc_increment)
{
alloc_increment=max((8192-MALLOC_OVERHEAD)/element_size,16);
if (init_alloc > 8 && alloc_increment > init_alloc * 2)
alloc_increment=init_alloc*2;
}
if (!init_alloc)
init_alloc=alloc_increment;
array->elements=0;
array->max_element=init_alloc;
array->alloc_increment=alloc_increment;
array->size_of_element=element_size;
if (!(array->buffer=(char*) malloc(element_size*init_alloc)))
{
array->max_element=0;
return(TRUE);
}
return(FALSE);
}
my_bool ma_insert_dynamic(DYNAMIC_ARRAY *array, void *element)
{
void *buffer;
if (array->elements == array->max_element)
{ /* Call only when necessary */
if (!(buffer=ma_alloc_dynamic(array)))
return TRUE;
}
else
{
buffer=array->buffer+(array->elements * array->size_of_element);
array->elements++;
}
memcpy(buffer,element,(size_t) array->size_of_element);
return FALSE;
}
/* Alloc room for one element */
unsigned char *ma_alloc_dynamic(DYNAMIC_ARRAY *array)
{
if (array->elements == array->max_element)
{
char *new_ptr;
if (!(new_ptr=(char*) realloc(array->buffer,(array->max_element+
array->alloc_increment)*
array->size_of_element)))
return 0;
array->buffer=new_ptr;
array->max_element+=array->alloc_increment;
}
return (unsigned char *)array->buffer+(array->elements++ * array->size_of_element);
}
/* remove last element from array and return it */
unsigned char *ma_pop_dynamic(DYNAMIC_ARRAY *array)
{
if (array->elements)
return (unsigned char *)array->buffer+(--array->elements * array->size_of_element);
return 0;
}
my_bool ma_set_dynamic(DYNAMIC_ARRAY *array, void * element, uint idx)
{
if (idx >= array->elements)
{
if (idx >= array->max_element)
{
uint size;
char *new_ptr;
size=(idx+array->alloc_increment)/array->alloc_increment;
size*= array->alloc_increment;
if (!(new_ptr=(char*) realloc(array->buffer,size*
array->size_of_element)))
return TRUE;
array->buffer=new_ptr;
array->max_element=size;
}
memset((array->buffer+array->elements*array->size_of_element), 0,
(idx - array->elements)*array->size_of_element);
array->elements=idx+1;
}
memcpy(array->buffer+(idx * array->size_of_element),element,
(size_t) array->size_of_element);
return FALSE;
}
void ma_get_dynamic(DYNAMIC_ARRAY *array, void * element, uint idx)
{
if (idx >= array->elements)
{
memset(element, 0, array->size_of_element);
return;
}
memcpy(element,array->buffer+idx*array->size_of_element,
(size_t) array->size_of_element);
}
void ma_delete_dynamic(DYNAMIC_ARRAY *array)
{
if (array->buffer)
{
free(array->buffer);
array->buffer=0;
array->elements=array->max_element=0;
}
}
void ma_delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
{
char *ptr=array->buffer+array->size_of_element*idx;
array->elements--;
memmove(ptr,ptr+array->size_of_element,
(array->elements-idx)*array->size_of_element);
}
void ma_freeze_size(DYNAMIC_ARRAY *array)
{
uint elements=max(array->elements,1);
if (array->buffer && array->max_element != elements)
{
array->buffer=(char*) realloc(array->buffer,
elements*array->size_of_element);
array->max_element=elements;
}
}

1482
vendor/MDBC/libmariadb/ma_charset.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,508 @@
/* Copyright (C) 2010 - 2012 Sergei Golubchik and Monty Program Ab
2015-2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA */
/**
@file
Support code for the client side (libmariadb) plugins
Client plugins are somewhat different from server plugins, they are simpler.
They do not need to be installed or in any way explicitly loaded on the
client, they are loaded automatically on demand.
One client plugin per shared object, soname *must* match the plugin name.
There is no reference counting and no unloading either.
*/
/* Silence warnings about variable 'unused' being used. */
#define FORCE_INIT_OF_VARS 1
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_common.h>
#include <ma_string.h>
#include <ma_pthread.h>
#include "errmsg.h"
#include <mysql/client_plugin.h>
#ifndef WIN32
#include <dlfcn.h>
#endif
struct st_client_plugin_int {
struct st_client_plugin_int *next;
void *dlhandle;
struct st_mysql_client_plugin *plugin;
};
static my_bool initialized= 0;
static MA_MEM_ROOT mem_root;
static uint valid_plugins[][2]= {
{MYSQL_CLIENT_AUTHENTICATION_PLUGIN, MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION},
{MARIADB_CLIENT_PVIO_PLUGIN, MARIADB_CLIENT_PVIO_PLUGIN_INTERFACE_VERSION},
{MARIADB_CLIENT_TRACE_PLUGIN, MARIADB_CLIENT_TRACE_PLUGIN_INTERFACE_VERSION},
{MARIADB_CLIENT_REMOTEIO_PLUGIN, MARIADB_CLIENT_REMOTEIO_PLUGIN_INTERFACE_VERSION},
{MARIADB_CLIENT_CONNECTION_PLUGIN, MARIADB_CLIENT_CONNECTION_PLUGIN_INTERFACE_VERSION},
{0, 0}
};
/*
Loaded plugins are stored in a linked list.
The list is append-only, the elements are added to the head (like in a stack).
The elements are added under a mutex, but the list can be read and traversed
without any mutex because once an element is added to the list, it stays
there. The main purpose of a mutex is to prevent two threads from
loading the same plugin twice in parallel.
*/
struct st_client_plugin_int *plugin_list[MYSQL_CLIENT_MAX_PLUGINS + MARIADB_CLIENT_MAX_PLUGINS];
#ifdef THREAD
static pthread_mutex_t LOCK_load_client_plugin;
#endif
@EXTERNAL_PLUGINS@
struct st_mysql_client_plugin *mysql_client_builtins[]=
{
@BUILTIN_PLUGINS@
0
};
static int is_not_initialized(MYSQL *mysql, const char *name)
{
if (initialized)
return 0;
my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
SQLSTATE_UNKNOWN, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
name, "not initialized");
return 1;
}
static int get_plugin_nr(uint type)
{
uint i= 0;
for(; valid_plugins[i][1]; i++)
if (valid_plugins[i][0] == type)
return i;
return -1;
}
static const char *check_plugin_version(struct st_mysql_client_plugin *plugin, unsigned int version)
{
if (plugin->interface_version < version ||
(plugin->interface_version >> 8) > (version >> 8))
return "Incompatible client plugin interface";
return 0;
}
/**
finds a plugin in the list
@param name plugin name to search for
@param type plugin type
@note this does NOT necessarily need a mutex, take care!
@retval a pointer to a found plugin or 0
*/
static struct st_mysql_client_plugin *find_plugin(const char *name, int type)
{
struct st_client_plugin_int *p;
int plugin_nr= get_plugin_nr(type);
DBUG_ASSERT(initialized);
if (plugin_nr == -1)
return 0;
if (!name)
return plugin_list[plugin_nr]->plugin;
for (p= plugin_list[plugin_nr]; p; p= p->next)
{
if (strcmp(p->plugin->name, name) == 0)
return p->plugin;
}
return NULL;
}
/**
verifies the plugin and adds it to the list
@param mysql MYSQL structure (for error reporting)
@param plugin plugin to install
@param dlhandle a handle to the shared object (returned by dlopen)
or 0 if the plugin was not dynamically loaded
@param argc number of arguments in the 'va_list args'
@param args arguments passed to the plugin initialization function
@retval a pointer to an installed plugin or 0
*/
static struct st_mysql_client_plugin *
add_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin, void *dlhandle,
int argc, va_list args)
{
const char *errmsg;
struct st_client_plugin_int plugin_int, *p;
char errbuf[1024];
int plugin_nr;
DBUG_ASSERT(initialized);
plugin_int.plugin= plugin;
plugin_int.dlhandle= dlhandle;
if ((plugin_nr= get_plugin_nr(plugin->type)) == -1)
{
errmsg= "Unknown client plugin type";
goto err1;
}
if ((errmsg= check_plugin_version(plugin, valid_plugins[plugin_nr][1])))
goto err1;
/* Call the plugin initialization function, if any */
if (plugin->init && plugin->init(errbuf, sizeof(errbuf), argc, args))
{
errmsg= errbuf;
goto err1;
}
p= (struct st_client_plugin_int *)
ma_memdup_root(&mem_root, (char *)&plugin_int, sizeof(plugin_int));
if (!p)
{
errmsg= "Out of memory";
goto err2;
}
p->next= plugin_list[plugin_nr];
plugin_list[plugin_nr]= p;
return plugin;
err2:
if (plugin->deinit)
plugin->deinit();
err1:
my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), plugin->name, errmsg);
if (dlhandle)
(void)dlclose(dlhandle);
return NULL;
}
/**
Loads plugins which are specified in the environment variable
LIBMYSQL_PLUGINS.
Multiple plugins must be separated by semicolon. This function doesn't
return or log an error.
The function is be called by mysql_client_plugin_init
@todo
Support extended syntax, passing parameters to plugins, for example
LIBMYSQL_PLUGINS="plugin1(param1,param2);plugin2;..."
or
LIBMYSQL_PLUGINS="plugin1=int:param1,str:param2;plugin2;..."
*/
static void load_env_plugins(MYSQL *mysql)
{
char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
if (ma_check_env_str(s))
return;
free_env= strdup(s);
plugs= s= free_env;
do {
if ((s= strchr(plugs, ';')))
*s= '\0';
mysql_load_plugin(mysql, plugs, -1, 0);
plugs= s + 1;
} while (s);
free(free_env);
}
/********** extern functions to be used by libmariadb *********************/
/**
Initializes the client plugin layer.
This function must be called before any other client plugin function.
@retval 0 successful
@retval != 0 error occurred
*/
int mysql_client_plugin_init()
{
MYSQL mysql;
struct st_mysql_client_plugin **builtin;
va_list unused;
LINT_INIT_STRUCT(unused);
if (initialized)
return 0;
memset(&mysql, 0, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */
pthread_mutex_init(&LOCK_load_client_plugin, NULL);
ma_init_alloc_root(&mem_root, 128, 128);
memset(&plugin_list, 0, sizeof(plugin_list));
initialized= 1;
pthread_mutex_lock(&LOCK_load_client_plugin);
for (builtin= mysql_client_builtins; *builtin; builtin++)
add_plugin(&mysql, *builtin, 0, 0, unused);
pthread_mutex_unlock(&LOCK_load_client_plugin);
load_env_plugins(&mysql);
return 0;
}
/**
Deinitializes the client plugin layer.
Unloades all client plugins and frees any associated resources.
*/
void mysql_client_plugin_deinit()
{
int i;
struct st_client_plugin_int *p;
if (!initialized)
return;
for (i=0; i < MYSQL_CLIENT_MAX_PLUGINS; i++)
for (p= plugin_list[i]; p; p= p->next)
{
if (p->plugin->deinit)
p->plugin->deinit();
if (p->dlhandle)
(void)dlclose(p->dlhandle);
}
memset(&plugin_list, 0, sizeof(plugin_list));
initialized= 0;
ma_free_root(&mem_root, MYF(0));
pthread_mutex_destroy(&LOCK_load_client_plugin);
}
/************* public facing functions, for client consumption *********/
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin * STDCALL
mysql_client_register_plugin(MYSQL *mysql,
struct st_mysql_client_plugin *plugin)
{
va_list unused;
LINT_INIT_STRUCT(unused);
if (is_not_initialized(mysql, plugin->name))
return NULL;
pthread_mutex_lock(&LOCK_load_client_plugin);
/* make sure the plugin wasn't loaded meanwhile */
if (find_plugin(plugin->name, plugin->type))
{
my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
SQLSTATE_UNKNOWN, ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
plugin->name, "it is already loaded");
plugin= NULL;
}
else
plugin= add_plugin(mysql, plugin, 0, 0, unused);
pthread_mutex_unlock(&LOCK_load_client_plugin);
return plugin;
}
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin * STDCALL
mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
int argc, va_list args)
{
const char *errmsg;
#ifdef _WIN32
char errbuf[1024];
#endif
char dlpath[FN_REFLEN+1];
void *sym, *dlhandle = NULL;
struct st_mysql_client_plugin *plugin;
char *env_plugin_dir= getenv("MARIADB_PLUGIN_DIR");
CLEAR_CLIENT_ERROR(mysql);
if (is_not_initialized(mysql, name))
return NULL;
pthread_mutex_lock(&LOCK_load_client_plugin);
/* make sure the plugin wasn't loaded meanwhile */
if (type >= 0 && find_plugin(name, type))
{
errmsg= "it is already loaded";
goto err;
}
/* Compile dll path */
#ifndef WIN32
snprintf(dlpath, sizeof(dlpath) - 1, "%s/%s%s",
mysql->options.extension && mysql->options.extension->plugin_dir ?
mysql->options.extension->plugin_dir : (env_plugin_dir) ? env_plugin_dir :
MARIADB_PLUGINDIR, name, SO_EXT);
#else
{
char *p= (mysql->options.extension && mysql->options.extension->plugin_dir) ?
mysql->options.extension->plugin_dir : env_plugin_dir;
snprintf(dlpath, sizeof(dlpath), "%s%s%s%s", p ? p : "", p ? "\\" : "", name, SO_EXT);
}
#endif
if (strpbrk(name, "()[]!@#$%^&/*;.,'?\\"))
{
errmsg= "invalid plugin name";
goto err;
}
/* Open new dll handle */
if (!(dlhandle= dlopen((const char *)dlpath, RTLD_NOW)))
{
#ifdef _WIN32
char winmsg[255];
size_t len;
winmsg[0] = 0;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
winmsg, 255, NULL);
len= strlen(winmsg);
while (len > 0 && (winmsg[len - 1] == '\n' || winmsg[len - 1] == '\r'))
len--;
if (len)
winmsg[len] = 0;
snprintf(errbuf, sizeof(errbuf), "%s Library path is '%s'", winmsg, dlpath);
errmsg= errbuf;
#else
errmsg= dlerror();
#endif
goto err;
}
if (!(sym= dlsym(dlhandle, plugin_declarations_sym)))
{
errmsg= "not a plugin";
(void)dlclose(dlhandle);
goto err;
}
plugin= (struct st_mysql_client_plugin*)sym;
if (type >=0 && type != plugin->type)
{
errmsg= "type mismatch";
goto err;
}
if (strcmp(name, plugin->name))
{
errmsg= "name mismatch";
goto err;
}
if (type < 0 && find_plugin(name, plugin->type))
{
errmsg= "it is already loaded";
goto err;
}
plugin= add_plugin(mysql, plugin, dlhandle, argc, args);
pthread_mutex_unlock(&LOCK_load_client_plugin);
return plugin;
err:
if (dlhandle)
dlclose(dlhandle);
pthread_mutex_unlock(&LOCK_load_client_plugin);
my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, errmsg);
return NULL;
}
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin * STDCALL
mysql_load_plugin(MYSQL *mysql, const char *name, int type, int argc, ...)
{
struct st_mysql_client_plugin *p;
va_list args;
va_start(args, argc);
p= mysql_load_plugin_v(mysql, name, type, argc, args);
va_end(args);
return p;
}
/* see <mysql/client_plugin.h> for a full description */
struct st_mysql_client_plugin * STDCALL
mysql_client_find_plugin(MYSQL *mysql, const char *name, int type)
{
struct st_mysql_client_plugin *p;
int plugin_nr= get_plugin_nr(type);
if (is_not_initialized(mysql, name))
return NULL;
if (plugin_nr == -1)
{
my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN,
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, "invalid type");
}
if ((p= find_plugin(name, type)))
return p;
/* not found, load it */
return mysql_load_plugin(mysql, name, type, 0);
}

90
vendor/MDBC/libmariadb/ma_compress.c vendored Normal file
View File

@ -0,0 +1,90 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/* Written by Sinisa Milivojevic <sinisa@coresinc.com> */
#include <ma_global.h>
#ifdef HAVE_COMPRESS
#include <ma_sys.h>
#include <ma_string.h>
#include <zlib.h>
/*
** This replaces the packet with a compressed packet
** Returns 1 on error
** *complen is 0 if the packet wasn't compressed
*/
my_bool _mariadb_compress(unsigned char *packet, size_t *len, size_t *complen)
{
if (*len < MIN_COMPRESS_LENGTH)
*complen=0;
else
{
unsigned char *compbuf=_mariadb_compress_alloc(packet,len,complen);
if (!compbuf)
return *complen ? 0 : 1;
memcpy(packet,compbuf,*len);
free(compbuf);
}
return 0;
}
unsigned char *_mariadb_compress_alloc(const unsigned char *packet, size_t *len, size_t *complen)
{
unsigned char *compbuf;
*complen = *len * 120 / 100 + 12;
if (!(compbuf = (unsigned char *) malloc(*complen)))
return 0; /* Not enough memory */
if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
(uLong) *len ) != Z_OK)
{
free(compbuf);
return 0;
}
if (*complen >= *len)
{
*complen=0;
free(compbuf);
return 0;
}
swap(size_t,*len,*complen); /* *len is now packet length */
return compbuf;
}
my_bool _mariadb_uncompress (unsigned char *packet, size_t *len, size_t *complen)
{
if (*complen) /* If compressed */
{
unsigned char *compbuf = (unsigned char *) malloc (*complen);
if (!compbuf)
return 1; /* Not enough memory */
if (uncompress((Bytef*) compbuf, (uLongf *)complen, (Bytef*) packet, (uLongf)*len) != Z_OK)
{ /* Probably wrong packet */
free(compbuf);
return 1;
}
*len = *complen;
memcpy(packet,compbuf,*len);
free(compbuf);
}
else *complen= *len;
return 0;
}
#endif /* HAVE_COMPRESS */

726
vendor/MDBC/libmariadb/ma_context.c vendored Normal file
View File

@ -0,0 +1,726 @@
/*
Copyright 2011, 2012 Kristian Nielsen and Monty Program Ab
2016 MariaDB Corporation AB
This file is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU General Public License
along with this. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Implementation of async context spawning using Posix ucontext and
swapcontext().
*/
#include "ma_global.h"
#include "ma_string.h"
#include "ma_context.h"
#ifdef HAVE_VALGRIND
#include <valgrind/valgrind.h>
#endif
#ifdef MY_CONTEXT_USE_UCONTEXT
/*
The makecontext() only allows to pass integers into the created context :-(
We want to pass pointers, so we do it this kinda hackish way.
Anyway, it should work everywhere, and at least it does not break strict
aliasing.
*/
union pass_void_ptr_as_2_int {
int a[2];
void *p;
};
/*
We use old-style function definition here, as this is passed to
makecontext(). And the type of the makecontext() argument does not match
the actual type (as the actual type can differ from call to call).
*/
static void
my_context_spawn_internal(i0, i1)
int i0, i1;
{
int err;
struct my_context *c;
union pass_void_ptr_as_2_int u;
u.a[0]= i0;
u.a[1]= i1;
c= (struct my_context *)u.p;
(*c->user_func)(c->user_data);
c->active= 0;
err= setcontext(&c->base_context);
fprintf(stderr, "Aieie, setcontext() failed: %d (errno=%d)\n", err, errno);
}
int
my_context_continue(struct my_context *c)
{
int err;
if (!c->active)
return 0;
err= swapcontext(&c->base_context, &c->spawned_context);
if (err)
{
fprintf(stderr, "Aieie, swapcontext() failed: %d (errno=%d)\n",
err, errno);
return -1;
}
return c->active;
}
int
my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
{
int err;
union pass_void_ptr_as_2_int u;
err= getcontext(&c->spawned_context);
if (err)
return -1;
c->spawned_context.uc_stack.ss_sp= c->stack;
c->spawned_context.uc_stack.ss_size= c->stack_size;
c->spawned_context.uc_link= NULL;
c->user_func= f;
c->user_data= d;
c->active= 1;
u.p= c;
makecontext(&c->spawned_context, my_context_spawn_internal, 2,
u.a[0], u.a[1]);
return my_context_continue(c);
}
int
my_context_yield(struct my_context *c)
{
int err;
if (!c->active)
return -1;
err= swapcontext(&c->spawned_context, &c->base_context);
if (err)
return -1;
return 0;
}
int
my_context_init(struct my_context *c, size_t stack_size)
{
#if SIZEOF_CHARP > SIZEOF_INT*2
#error Error: Unable to store pointer in 2 ints on this architecture
#endif
memset(c, 0, sizeof(*c));
if (!(c->stack= malloc(stack_size)))
return -1; /* Out of memory */
c->stack_size= stack_size;
#ifdef HAVE_VALGRIND
c->valgrind_stack_id=
VALGRIND_STACK_REGISTER(c->stack, ((unsigned char *)(c->stack))+stack_size);
#endif
return 0;
}
void
my_context_destroy(struct my_context *c)
{
if (c->stack)
{
#ifdef HAVE_VALGRIND
VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
#endif
free(c->stack);
}
}
#endif /* MY_CONTEXT_USE_UCONTEXT */
#ifdef MY_CONTEXT_USE_X86_64_GCC_ASM
/*
GCC-amd64 implementation of my_context.
This is slightly optimized in the common case where we never yield
(eg. fetch next row and it is already fully received in buffer). In this
case we do not need to restore registers at return (though we still need to
save them as we cannot know if we will yield or not in advance).
*/
#include <stdint.h>
#include <stdlib.h>
/*
Layout of saved registers etc.
Since this is accessed through gcc inline assembler, it is simpler to just
use numbers than to try to define nice constants or structs.
0 0 %rsp
1 8 %rbp
2 16 %rbx
3 24 %r12
4 32 %r13
5 40 %r14
6 48 %r15
7 56 %rip for done
8 64 %rip for yield/continue
*/
int
my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
{
int ret;
/*
There are 6 callee-save registers we need to save and restore when
suspending and continuing, plus stack pointer %rsp and instruction pointer
%rip.
However, if we never suspend, the user-supplied function will in any case
restore the 6 callee-save registers, so we can avoid restoring them in
this case.
*/
__asm__ __volatile__
(
"movq %%rsp, (%[save])\n\t"
"movq %[stack], %%rsp\n\t"
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 && !defined(__INTEL_COMPILER)
/*
This emits a DWARF DW_CFA_undefined directive to make the return address
undefined. This indicates that this is the top of the stack frame, and
helps tools that use DWARF stack unwinding to obtain stack traces.
(I use numeric constant to avoid a dependency on libdwarf includes).
*/
".cfi_escape 0x07, 16\n\t"
#endif
"movq %%rbp, 8(%[save])\n\t"
"movq %%rbx, 16(%[save])\n\t"
"movq %%r12, 24(%[save])\n\t"
"movq %%r13, 32(%[save])\n\t"
"movq %%r14, 40(%[save])\n\t"
"movq %%r15, 48(%[save])\n\t"
"leaq 1f(%%rip), %%rax\n\t"
"leaq 2f(%%rip), %%rcx\n\t"
"movq %%rax, 56(%[save])\n\t"
"movq %%rcx, 64(%[save])\n\t"
/*
Constraint below puts the argument to the user function into %rdi, as
needed for the calling convention.
*/
"callq *%[f]\n\t"
"jmpq *56(%[save])\n"
/*
Come here when operation is done.
We do not need to restore callee-save registers, as the called function
will do this for us if needed.
*/
"1:\n\t"
"movq (%[save]), %%rsp\n\t"
"xorl %[ret], %[ret]\n\t"
"jmp 3f\n"
/* Come here when operation was suspended. */
"2:\n\t"
"movl $1, %[ret]\n"
"3:\n"
: [ret] "=a" (ret),
[f] "+S" (f),
/* Need this in %rdi to follow calling convention. */
[d] "+D" (d)
: [stack] "a" (c->stack_top),
/* Need this in callee-save register to preserve in function call. */
[save] "b" (&c->save[0])
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc"
);
return ret;
}
int
my_context_continue(struct my_context *c)
{
int ret;
__asm__ __volatile__
(
"movq (%[save]), %%rax\n\t"
"movq %%rsp, (%[save])\n\t"
"movq %%rax, %%rsp\n\t"
"movq 8(%[save]), %%rax\n\t"
"movq %%rbp, 8(%[save])\n\t"
"movq %%rax, %%rbp\n\t"
"movq 24(%[save]), %%rax\n\t"
"movq %%r12, 24(%[save])\n\t"
"movq %%rax, %%r12\n\t"
"movq 32(%[save]), %%rax\n\t"
"movq %%r13, 32(%[save])\n\t"
"movq %%rax, %%r13\n\t"
"movq 40(%[save]), %%rax\n\t"
"movq %%r14, 40(%[save])\n\t"
"movq %%rax, %%r14\n\t"
"movq 48(%[save]), %%rax\n\t"
"movq %%r15, 48(%[save])\n\t"
"movq %%rax, %%r15\n\t"
"leaq 1f(%%rip), %%rax\n\t"
"leaq 2f(%%rip), %%rcx\n\t"
"movq %%rax, 56(%[save])\n\t"
"movq 64(%[save]), %%rax\n\t"
"movq %%rcx, 64(%[save])\n\t"
"movq 16(%[save]), %%rcx\n\t"
"movq %%rbx, 16(%[save])\n\t"
"movq %%rcx, %%rbx\n\t"
"jmpq *%%rax\n"
/*
Come here when operation is done.
Be sure to use the same callee-save register for %[save] here and in
my_context_spawn(), so we preserve the value correctly at this point.
*/
"1:\n\t"
"movq (%[save]), %%rsp\n\t"
"movq 8(%[save]), %%rbp\n\t"
/* %rbx is preserved from my_context_spawn() in this case. */
"movq 24(%[save]), %%r12\n\t"
"movq 32(%[save]), %%r13\n\t"
"movq 40(%[save]), %%r14\n\t"
"movq 48(%[save]), %%r15\n\t"
"xorl %[ret], %[ret]\n\t"
"jmp 3f\n"
/* Come here when operation is suspended. */
"2:\n\t"
"movl $1, %[ret]\n"
"3:\n"
: [ret] "=a" (ret)
: /* Need this in callee-save register to preserve in function call. */
[save] "b" (&c->save[0])
: "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "memory", "cc"
);
return ret;
}
int
my_context_yield(struct my_context *c)
{
uint64_t *save= &c->save[0];
__asm__ __volatile__
(
"movq (%[save]), %%rax\n\t"
"movq %%rsp, (%[save])\n\t"
"movq %%rax, %%rsp\n\t"
"movq 8(%[save]), %%rax\n\t"
"movq %%rbp, 8(%[save])\n\t"
"movq %%rax, %%rbp\n\t"
"movq 16(%[save]), %%rax\n\t"
"movq %%rbx, 16(%[save])\n\t"
"movq %%rax, %%rbx\n\t"
"movq 24(%[save]), %%rax\n\t"
"movq %%r12, 24(%[save])\n\t"
"movq %%rax, %%r12\n\t"
"movq 32(%[save]), %%rax\n\t"
"movq %%r13, 32(%[save])\n\t"
"movq %%rax, %%r13\n\t"
"movq 40(%[save]), %%rax\n\t"
"movq %%r14, 40(%[save])\n\t"
"movq %%rax, %%r14\n\t"
"movq 48(%[save]), %%rax\n\t"
"movq %%r15, 48(%[save])\n\t"
"movq %%rax, %%r15\n\t"
"movq 64(%[save]), %%rax\n\t"
"leaq 1f(%%rip), %%rcx\n\t"
"movq %%rcx, 64(%[save])\n\t"
"jmpq *%%rax\n"
"1:\n"
: [save] "+D" (save)
:
: "rax", "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc"
);
return 0;
}
int
my_context_init(struct my_context *c, size_t stack_size)
{
memset(c, 0, sizeof(*c));
if (!(c->stack_bot= malloc(stack_size)))
return -1; /* Out of memory */
/*
The x86_64 ABI specifies 16-byte stack alignment.
Also put two zero words at the top of the stack.
*/
c->stack_top= (void *)
(( ((intptr)c->stack_bot + stack_size) & ~(intptr)0xf) - 16);
memset(c->stack_top, 0, 16);
#ifdef HAVE_VALGRIND
c->valgrind_stack_id=
VALGRIND_STACK_REGISTER(c->stack_bot, c->stack_top);
#endif
return 0;
}
void
my_context_destroy(struct my_context *c)
{
if (c->stack_bot)
{
free(c->stack_bot);
#ifdef HAVE_VALGRIND
VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
#endif
}
}
#endif /* MY_CONTEXT_USE_X86_64_GCC_ASM */
#ifdef MY_CONTEXT_USE_I386_GCC_ASM
/*
GCC-i386 implementation of my_context.
This is slightly optimized in the common case where we never yield
(eg. fetch next row and it is already fully received in buffer). In this
case we do not need to restore registers at return (though we still need to
save them as we cannot know if we will yield or not in advance).
*/
#include <stdint.h>
#include <stdlib.h>
/*
Layout of saved registers etc.
Since this is accessed through gcc inline assembler, it is simpler to just
use numbers than to try to define nice constants or structs.
0 0 %esp
1 4 %ebp
2 8 %ebx
3 12 %esi
4 16 %edi
5 20 %eip for done
6 24 %eip for yield/continue
*/
int
my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
{
int ret;
/*
There are 4 callee-save registers we need to save and restore when
suspending and continuing, plus stack pointer %esp and instruction pointer
%eip.
However, if we never suspend, the user-supplied function will in any case
restore the 4 callee-save registers, so we can avoid restoring them in
this case.
*/
__asm__ __volatile__
(
"movl %%esp, (%[save])\n\t"
"movl %[stack], %%esp\n\t"
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 && !defined(__INTEL_COMPILER)
/*
This emits a DWARF DW_CFA_undefined directive to make the return address
undefined. This indicates that this is the top of the stack frame, and
helps tools that use DWARF stack unwinding to obtain stack traces.
(I use numeric constant to avoid a dependency on libdwarf includes).
*/
".cfi_escape 0x07, 8\n\t"
#endif
/* Push the parameter on the stack. */
"pushl %[d]\n\t"
"movl %%ebp, 4(%[save])\n\t"
"movl %%ebx, 8(%[save])\n\t"
"movl %%esi, 12(%[save])\n\t"
"movl %%edi, 16(%[save])\n\t"
/* Get label addresses in -fPIC-compatible way (no pc-relative on 32bit) */
"call 1f\n"
"1:\n\t"
"popl %%eax\n\t"
"addl $(2f-1b), %%eax\n\t"
"movl %%eax, 20(%[save])\n\t"
"addl $(3f-2f), %%eax\n\t"
"movl %%eax, 24(%[save])\n\t"
"call *%[f]\n\t"
"jmp *20(%[save])\n"
/*
Come here when operation is done.
We do not need to restore callee-save registers, as the called function
will do this for us if needed.
*/
"2:\n\t"
"movl (%[save]), %%esp\n\t"
"xorl %[ret], %[ret]\n\t"
"jmp 4f\n"
/* Come here when operation was suspended. */
"3:\n\t"
"movl $1, %[ret]\n"
"4:\n"
: [ret] "=a" (ret),
[f] "+c" (f),
[d] "+d" (d)
: [stack] "a" (c->stack_top),
/* Need this in callee-save register to preserve across function call. */
[save] "D" (&c->save[0])
: "memory", "cc"
);
return ret;
}
int
my_context_continue(struct my_context *c)
{
int ret;
__asm__ __volatile__
(
"movl (%[save]), %%eax\n\t"
"movl %%esp, (%[save])\n\t"
"movl %%eax, %%esp\n\t"
"movl 4(%[save]), %%eax\n\t"
"movl %%ebp, 4(%[save])\n\t"
"movl %%eax, %%ebp\n\t"
"movl 8(%[save]), %%eax\n\t"
"movl %%ebx, 8(%[save])\n\t"
"movl %%eax, %%ebx\n\t"
"movl 12(%[save]), %%eax\n\t"
"movl %%esi, 12(%[save])\n\t"
"movl %%eax, %%esi\n\t"
"movl 24(%[save]), %%eax\n\t"
"call 1f\n"
"1:\n\t"
"popl %%ecx\n\t"
"addl $(2f-1b), %%ecx\n\t"
"movl %%ecx, 20(%[save])\n\t"
"addl $(3f-2f), %%ecx\n\t"
"movl %%ecx, 24(%[save])\n\t"
/* Must restore %edi last as it is also our %[save] register. */
"movl 16(%[save]), %%ecx\n\t"
"movl %%edi, 16(%[save])\n\t"
"movl %%ecx, %%edi\n\t"
"jmp *%%eax\n"
/*
Come here when operation is done.
Be sure to use the same callee-save register for %[save] here and in
my_context_spawn(), so we preserve the value correctly at this point.
*/
"2:\n\t"
"movl (%[save]), %%esp\n\t"
"movl 4(%[save]), %%ebp\n\t"
"movl 8(%[save]), %%ebx\n\t"
"movl 12(%[save]), %%esi\n\t"
"movl 16(%[save]), %%edi\n\t"
"xorl %[ret], %[ret]\n\t"
"jmp 4f\n"
/* Come here when operation is suspended. */
"3:\n\t"
"movl $1, %[ret]\n"
"4:\n"
: [ret] "=a" (ret)
: /* Need this in callee-save register to preserve in function call. */
[save] "D" (&c->save[0])
: "ecx", "edx", "memory", "cc"
);
return ret;
}
int
my_context_yield(struct my_context *c)
{
uint64_t *save= &c->save[0];
__asm__ __volatile__
(
"movl (%[save]), %%eax\n\t"
"movl %%esp, (%[save])\n\t"
"movl %%eax, %%esp\n\t"
"movl 4(%[save]), %%eax\n\t"
"movl %%ebp, 4(%[save])\n\t"
"movl %%eax, %%ebp\n\t"
"movl 8(%[save]), %%eax\n\t"
"movl %%ebx, 8(%[save])\n\t"
"movl %%eax, %%ebx\n\t"
"movl 12(%[save]), %%eax\n\t"
"movl %%esi, 12(%[save])\n\t"
"movl %%eax, %%esi\n\t"
"movl 16(%[save]), %%eax\n\t"
"movl %%edi, 16(%[save])\n\t"
"movl %%eax, %%edi\n\t"
"movl 24(%[save]), %%eax\n\t"
"call 1f\n"
"1:\n\t"
"popl %%ecx\n\t"
"addl $(2f-1b), %%ecx\n\t"
"movl %%ecx, 24(%[save])\n\t"
"jmp *%%eax\n"
"2:\n"
: [save] "+d" (save)
:
: "eax", "ecx", "memory", "cc"
);
return 0;
}
int
my_context_init(struct my_context *c, size_t stack_size)
{
memset(c, 0, sizeof(*c));
if (!(c->stack_bot= malloc(stack_size)))
return -1; /* Out of memory */
c->stack_top= (void *)
(( ((intptr)c->stack_bot + stack_size) & ~(intptr)0xf) - 16);
memset(c->stack_top, 0, 16);
#ifdef HAVE_VALGRIND
c->valgrind_stack_id=
VALGRIND_STACK_REGISTER(c->stack_bot, c->stack_top);
#endif
return 0;
}
void
my_context_destroy(struct my_context *c)
{
if (c->stack_bot)
{
free(c->stack_bot);
#ifdef HAVE_VALGRIND
VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
#endif
}
}
#endif /* MY_CONTEXT_USE_I386_GCC_ASM */
#ifdef MY_CONTEXT_USE_WIN32_FIBERS
int
my_context_yield(struct my_context *c)
{
c->return_value= 1;
SwitchToFiber(c->app_fiber);
return 0;
}
static void WINAPI
my_context_trampoline(void *p)
{
struct my_context *c= (struct my_context *)p;
/*
Reuse the Fiber by looping infinitely, each time we are scheduled we
spawn the appropriate function and switch back when it is done.
This way we avoid the overhead of CreateFiber() for every asynchroneous
operation.
*/
for(;;)
{
(*(c->user_func))(c->user_arg);
c->return_value= 0;
SwitchToFiber(c->app_fiber);
}
}
int
my_context_init(struct my_context *c, size_t stack_size)
{
memset(c, 0, sizeof(*c));
c->lib_fiber= CreateFiber(stack_size, my_context_trampoline, c);
if (c->lib_fiber)
return 0;
return -1;
}
void
my_context_destroy(struct my_context *c)
{
if (c->lib_fiber)
{
DeleteFiber(c->lib_fiber);
c->lib_fiber= NULL;
}
}
int
my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
{
c->user_func= f;
c->user_arg= d;
return my_context_continue(c);
}
int
my_context_continue(struct my_context *c)
{
void *current_fiber= IsThreadAFiber() ? GetCurrentFiber() : ConvertThreadToFiber(c);
c->app_fiber= current_fiber;
SwitchToFiber(c->lib_fiber);
return c->return_value;
}
#endif /* MY_CONTEXT_USE_WIN32_FIBERS */
#ifdef MY_CONTEXT_DISABLE
int
my_context_continue(struct my_context *c)
{
return -1;
}
int
my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
{
return -1;
}
int
my_context_yield(struct my_context *c)
{
return -1;
}
int
my_context_init(struct my_context *c, size_t stack_size)
{
return -1; /* Out of memory */
}
void
my_context_destroy(struct my_context *c)
{
}
#endif

370
vendor/MDBC/libmariadb/ma_default.c vendored Normal file
View File

@ -0,0 +1,370 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
#include <ma_global.h>
#include <ma_sys.h>
#include "ma_string.h"
#include <ctype.h>
#include "mariadb_ctype.h"
#include <mysql.h>
#include <ma_common.h>
#include <mariadb/ma_io.h>
#ifdef _WIN32
#include <io.h>
#include "shlwapi.h"
static const char *ini_exts[]= {"ini", "cnf", 0};
#define R_OK 4
#else
#include <unistd.h>
static const char *ini_exts[]= {"cnf", 0};
#endif
char **configuration_dirs= NULL;
#define MAX_CONFIG_DIRS 6
my_bool _mariadb_read_options(MYSQL *mysql,
const char *config_dir,
const char *config_file,
const char *group,
unsigned int recursion);
static int add_cfg_dir(char **cfg_dirs, const char *directory)
{
int i;
for (i = 0; i < MAX_CONFIG_DIRS && cfg_dirs[i]; i++)
if (!strcmp(cfg_dirs[i], directory)) /* already present */
return 0;
if (i < MAX_CONFIG_DIRS) {
cfg_dirs[i]= strdup(directory);
return 0;
}
return 1;
}
void release_configuration_dirs()
{
if (configuration_dirs)
{
int i= 0;
while (configuration_dirs[i])
free(configuration_dirs[i++]);
free(configuration_dirs);
}
}
char **get_default_configuration_dirs()
{
#ifdef _WIN32
char dirname[FN_REFLEN];
#endif
char *env;
configuration_dirs= (char **)calloc(1, (MAX_CONFIG_DIRS + 1) * sizeof(char *));
if (!configuration_dirs)
goto end;
#ifdef _WIN32
/* On Windows operating systems configuration files are stored in
1. System Windows directory
2. System directory
3. Windows directory
4. C:\
*/
if (!GetSystemWindowsDirectory(dirname, FN_REFLEN) ||
add_cfg_dir(configuration_dirs, dirname))
goto error;
if (!GetWindowsDirectory(dirname, FN_REFLEN) ||
add_cfg_dir(configuration_dirs, dirname))
goto error;
if (add_cfg_dir(configuration_dirs, "C:"))
goto error;
if (GetModuleFileName(NULL, dirname, FN_REFLEN))
{
PathRemoveFileSpec(dirname);
if (add_cfg_dir(configuration_dirs, dirname))
goto error;
}
#else
/* on *nix platforms configuration files are stored in
1. SYSCONFDIR (if build happens inside server package, or
-DDEFAULT_SYSCONFDIR was specified
2. /etc
3. /etc/mysql
*/
#ifdef DEFAULT_SYSCONFDIR
if (add_cfg_dir(configuration_dirs, DEFAULT_SYSCONFDIR))
goto error;
#else
if (add_cfg_dir(configuration_dirs, "/etc"))
goto error;
if (add_cfg_dir(configuration_dirs, "/etc/mysql"))
goto error;
#endif
#endif
/* CONC-537: Read configuration files from MYSQL_HOME directory only if
MARIADB_HOME was not set */
if (!(env= getenv("MARIADB_HOME")))
env= getenv("MYSQL_HOME");
if (env && add_cfg_dir(configuration_dirs, env))
goto error;
end:
return configuration_dirs;
error:
return NULL;
}
extern my_bool _mariadb_set_conf_option(MYSQL *mysql, const char *config_option, const char *config_value);
static my_bool is_group(char *ptr, const char **groups)
{
while (*groups)
{
if (!strcmp(ptr, *groups))
return 1;
groups++;
}
return 0;
}
static my_bool _mariadb_read_options_from_file(MYSQL *mysql,
const char *config_file,
const char *group,
unsigned int recursion)
{
uint line=0;
my_bool read_values= 0, found_group= 0, is_escaped= 0, is_quoted= 0;
char buff[4096],*ptr,*end,*value, *key= 0, *optval;
MA_FILE *file= NULL;
my_bool rc= 1;
const char *groups[5]= {"client",
"client-server",
"client-mariadb",
group,
NULL};
my_bool (*set_option)(MYSQL *mysql, const char *config_option, const char *config_value);
/* if a plugin registered a hook we will call this hook, otherwise
* default (_mariadb_set_conf_option) will be called */
if (mysql->options.extension && mysql->options.extension->set_option)
set_option= mysql->options.extension->set_option;
else
set_option= _mariadb_set_conf_option;
if (!(file = ma_open(config_file, "r", NULL)))
goto err;
while (ma_gets(buff,sizeof(buff)-1,file))
{
line++;
key= 0;
/* Ignore comment and empty lines */
for (ptr=buff ; isspace(*ptr) ; ptr++ );
if (!is_escaped && (*ptr == '\"' || *ptr== '\''))
{
is_quoted= !is_quoted;
continue;
}
/* CONC- 327: !includedir and !include */
if (*ptr == '!')
{
char *val;
ptr++;
if (!(val= strchr(ptr, ' ')))
continue;
*val++= 0;
end= strchr(val, 0);
for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */
*end= 0;
if (!strcmp(ptr, "includedir"))
_mariadb_read_options(mysql, (const char *)val, NULL, group, recursion + 1);
else if (!strcmp(ptr, "include"))
_mariadb_read_options(mysql, NULL, (const char *)val, group, recursion + 1);
continue;
}
if (*ptr == '#' || *ptr == ';' || !*ptr)
continue;
is_escaped= (*ptr == '\\');
if (*ptr == '[') /* Group name */
{
found_group=1;
if (!(end=(char *) strchr(++ptr,']')))
{
/* todo: set error */
goto err;
}
for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */
end[0]=0;
read_values= is_group(ptr, groups);
continue;
}
if (!found_group)
{
/* todo: set error */
goto err;
}
if (!read_values)
continue;
if (!(end=value=strchr(ptr,'=')))
{
end=strchr(ptr, '\0'); /* Option without argument */
set_option(mysql, ptr, NULL);
}
if (!key)
key= ptr;
for ( ; isspace(end[-1]) ; end--) ;
*end= 0;
if (value)
{
/* Remove pre- and end space */
char *value_end;
*value= 0;
value++;
ptr= value;
for ( ; isspace(*value); value++) ;
value_end=strchr(value, '\0');
*value_end= 0;
optval= ptr;
for ( ; isspace(value_end[-1]) ; value_end--) ;
/* remove possible quotes */
if (*value == '\'' || *value == '\"')
{
value++;
if (value_end[-1] == '\'' || value_end[-1] == '\"')
value_end--;
}
if (value_end < value) /* Empty string */
value_end=value;
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;
set_option(mysql, key, optval);
key= optval= 0;
}
}
rc= 0;
err:
if (file)
ma_close(file);
return rc;
}
my_bool _mariadb_read_options(MYSQL *mysql,
const char *config_dir,
const char *config_file,
const char *group,
unsigned int recursion)
{
int i= 0,
exts,
errors= 0;
char filename[FN_REFLEN + 1];
unsigned int recursion_stop= 64;
#ifndef _WIN32
char *env;
#endif
if (recursion >= recursion_stop)
return 1;
if (config_file && config_file[0])
return _mariadb_read_options_from_file(mysql, config_file, group, recursion);
if (config_dir && config_dir[0])
{
for (exts= 0; ini_exts[exts]; exts++)
{
snprintf(filename, FN_REFLEN,
"%s%cmy.%s", config_dir, FN_LIBCHAR, ini_exts[exts]);
if (!access(filename, R_OK))
errors+= _mariadb_read_options_from_file(mysql, filename, group, recursion);
}
return errors;
}
for (i=0; i < MAX_CONFIG_DIRS && configuration_dirs[i]; i++)
{
for (exts= 0; ini_exts[exts]; exts++)
{
snprintf(filename, FN_REFLEN,
"%s%cmy.%s", configuration_dirs[i], FN_LIBCHAR, ini_exts[exts]);
if (!access(filename, R_OK))
errors+= _mariadb_read_options_from_file(mysql, filename, group, recursion);
}
}
#ifndef _WIN32
/* special case: .my.cnf in Home directory */
if ((env= getenv("HOME")))
{
for (exts= 0; ini_exts[exts]; exts++)
{
snprintf(filename, FN_REFLEN,
"%s%c.my.%s", env, FN_LIBCHAR, ini_exts[exts]);
if (!access(filename, R_OK))
errors+= _mariadb_read_options_from_file(mysql, filename, group, recursion);
}
}
#endif
return errors;
}

1924
vendor/MDBC/libmariadb/ma_dtoa.c vendored Normal file

File diff suppressed because it is too large Load Diff

116
vendor/MDBC/libmariadb/ma_errmsg.c vendored Normal file
View File

@ -0,0 +1,116 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/* Error messages for clients */
/* error messages for the demon is in share/language/errmsg.sys */
#include <ma_global.h>
#include <ma_sys.h>
#include "errmsg.h"
#include <stdarg.h>
const char *SQLSTATE_UNKNOWN= "HY000";
const char *client_errors[]=
{
/* 2000 */ "Unknown error",
/* 2001 */ "Can't create UNIX socket (%d)",
/* 2002 */ "Can't connect to local server through socket '%-.64s' (%d)",
/* 2003 */ "Can't connect to server on '%-.64s' (%d)",
/* 2004 */ "Can't create TCP/IP socket (%d)",
/* 2005 */ "Unknown server host '%-.100s' (%d)",
/* 2006 */ "Server has gone away",
/* 2007 */ "Protocol mismatch. Server Version = %d Client Version = %d",
/* 2008 */ "Client run out of memory",
/* 2009 */ "Wrong host info",
/* 2010 */ "Localhost via UNIX socket",
/* 2011 */ "%-.64s via TCP/IP",
/* 2012 */ "Error in server handshake",
/* 2013 */ "Lost connection to server during query",
/* 2014 */ "Commands out of sync; you can't run this command now",
/* 2015 */ "%-.64s via named pipe",
/* 2016 */ "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
/* 2017 */ "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
/* 2018 */ "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
/* 2019 */ "Can't initialize character set %-.64s (path: %-.64s)",
/* 2020 */ "Got packet bigger than 'max_allowed_packet'",
/* 2021 */ "",
/* 2022 */ "",
/* 2023 */ "",
/* 2024 */ "",
/* 2025 */ "",
/* 2026 */ "SSL connection error: %-.100s",
/* 2027 */ "Received malformed packet",
/* 2028 */ "",
/* 2029 */ "",
/* 2030 */ "Statement is not prepared",
/* 2031 */ "No data supplied for parameters in prepared statement",
/* 2032 */ "Data truncated",
/* 2033 */ "",
/* 2034 */ "Invalid parameter number",
/* 2035 */ "Invalid buffer type: %d (parameter: %d)",
/* 2036 */ "Buffer type is not supported",
/* 2037 */ "Shared memory: %-.64s",
/* 2038 */ "Shared memory connection failed during %s. (%lu)",
/* 2039 */ "",
/* 2040 */ "",
/* 2041 */ "",
/* 2042 */ "",
/* 2043 */ "",
/* 2044 */ "",
/* 2045 */ "",
/* 2046 */ "",
/* 2047 */ "Wrong or unknown protocol",
/* 2048 */ "",
/* 2049 */ "Connection with old authentication protocol refused.",
/* 2050 */ "",
/* 2051 */ "",
/* 2052 */ "Prepared statement contains no metadata",
/* 2053 */ "",
/* 2054 */ "This feature is not implemented or disabled",
/* 2055 */ "Lost connection to server at '%s', system error: %d",
/* 2056 */ "Server closed statement due to a prior %s function call",
/* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset",
/* 2059 */ "Can't connect twice. Already connected",
/* 2058 */ "Plugin %s could not be loaded: %s",
/* 2059 */ "An attribute with same name already exists",
/* 2060 */ "Plugin doesn't support this function",
""
};
const char *mariadb_client_errors[] =
{
/* 5000 */ "Creating an event failed (Errorcode: %d)",
/* 5001 */ "Bind to local interface '-.%64s' failed (Errorcode: %d)",
/* 5002 */ "Connection type doesn't support asynchronous IO operations",
/* 5003 */ "Server doesn't support function '%s'",
/* 5004 */ "File '%s' not found (Errcode: %d)",
/* 5005 */ "Error reading file '%s' (Errcode: %d)",
/* 5006 */ "Bulk operation without parameters is not supported",
/* 5007 */ "Invalid statement handle",
/* 5008 */ "Unsupported version %d. Supported versions are in the range %d - %d",
""
};
const char ** NEAR my_errmsg[MAXMAPS]={0,0,0,0};
char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
void init_client_errs(void)
{
my_errmsg[CLIENT_ERRMAP] = &client_errors[0];
}

580
vendor/MDBC/libmariadb/ma_hashtbl.c vendored Normal file
View File

@ -0,0 +1,580 @@
/************************************************************************************
Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
Monty Program AB, 2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
Part of this code includes code from the PHP project which
is freely available from http://www.php.net
*************************************************************************************/
/* The hash functions used for saving keys */
/* One of key_length or key_length_offset must be given */
/* Key length of 0 isn't allowed */
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_string.h>
#include <mariadb_ctype.h>
#include "ma_hashtbl.h"
#define NO_RECORD ((uint) -1)
#define LOWFIND 1
#define LOWUSED 2
#define HIGHFIND 4
#define HIGHUSED 8
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
static void movelink(MA_HASHTBL_LINK *array,uint pos,uint next_link,uint newlink);
static uint calc_hashnr(const uchar *key,uint length);
static uint calc_hashnr_caseup(const uchar *key,uint length);
static int hashcmp(MA_HASHTBL *hash,MA_HASHTBL_LINK *pos,const uchar *key,uint length);
my_bool _ma_hashtbl_init(MA_HASHTBL *hash,uint size,uint key_offset,uint key_length,
hash_get_key get_key,
void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
{
hash->records=0;
if (ma_init_dynamic_array_ci(&hash->array,sizeof(MA_HASHTBL_LINK),size,0))
{
hash->free=0; /* Allow call to hash_free */
return(TRUE);
}
hash->key_offset=key_offset;
hash->key_length=key_length;
hash->blength=1;
hash->current_record= NO_RECORD; /* For the future */
hash->get_key=get_key;
hash->free=free_element;
hash->flags=flags;
if (flags & MA_HASHTBL_CASE_INSENSITIVE)
hash->calc_hashnr=calc_hashnr_caseup;
else
hash->calc_hashnr=calc_hashnr;
return(0);
}
void ma_hashtbl_free(MA_HASHTBL *hash)
{
if (hash->free)
{
uint i,records;
MA_HASHTBL_LINK *data=dynamic_element(&hash->array,0,MA_HASHTBL_LINK*);
for (i=0,records=hash->records ; i < records ; i++)
(*hash->free)(data[i].data);
hash->free=0;
}
ma_delete_dynamic(&hash->array);
hash->records=0;
return;
}
/* some helper functions */
/*
This function is char* instead of uchar* as HPUX11 compiler can't
handle inline functions that are not defined as native types
*/
static inline char*
hash_key(MA_HASHTBL *hash,const uchar *record,uint *length,my_bool first)
{
if (hash->get_key)
return (char *)(*hash->get_key)(record,(uint *)length,first);
*length=hash->key_length;
return (char*) record+hash->key_offset;
}
/* Calculate pos according to keys */
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
{
if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
return (hashnr & ((buffmax >> 1) -1));
}
static uint hash_rec_mask(MA_HASHTBL *hash,MA_HASHTBL_LINK *pos,uint buffmax,
uint maxlength)
{
uint length;
uchar *key= (uchar*) hash_key(hash,pos->data,&length,0);
return hash_mask((*hash->calc_hashnr)(key,length),buffmax,maxlength);
}
#ifndef NEW_MA_HASHTBL_FUNCTION
/* Calc hashvalue for a key */
static uint calc_hashnr(const uchar *key,uint length)
{
register uint nr=1, nr2=4;
while (length--)
{
nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);
nr2+=3;
}
return((uint) nr);
}
/* Calc hashvalue for a key, case independently */
static uint calc_hashnr_caseup(const uchar *key,uint length)
{
register uint nr=1, nr2=4;
while (length--)
{
nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
nr2+=3;
}
return((uint) nr);
}
#else
/*
* Fowler/Noll/Vo hash
*
* The basis of the hash algorithm was taken from an idea sent by email to the
* IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
* Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)
* later improved on their algorithm.
*
* The magic is in the interesting relationship between the special prime
* 16777619 (2^24 + 403) and 2^32 and 2^8.
*
* This hash produces the fewest collisions of any function that we've seen so
* far, and works well on both numbers and strings.
*/
uint calc_hashnr(const uchar *key, uint len)
{
const uchar *end=key+len;
uint hash;
for (hash = 0; key < end; key++)
{
hash *= 16777619;
hash ^= (uint) *(uchar*) key;
}
return (hash);
}
uint calc_hashnr_caseup(const uchar *key, uint len)
{
const uchar *end=key+len;
uint hash;
for (hash = 0; key < end; key++)
{
hash *= 16777619;
hash ^= (uint) (uchar) toupper(*key);
}
return (hash);
}
#endif
#ifndef __SUNPRO_C /* SUNPRO can't handle this */
static inline
#endif
unsigned int rec_hashnr(MA_HASHTBL *hash,const uchar *record)
{
uint length;
uchar *key= (uchar*) hash_key(hash,record,&length,0);
return (*hash->calc_hashnr)(key,length);
}
/* Search after a record based on a key */
/* Sets info->current_ptr to found record */
void* ma_hashtbl_search(MA_HASHTBL *hash,const uchar *key,uint length)
{
MA_HASHTBL_LINK *pos;
uint flag,idx;
flag=1;
if (hash->records)
{
idx=hash_mask((*hash->calc_hashnr)(key,length ? length :
hash->key_length),
hash->blength,hash->records);
do
{
pos= dynamic_element(&hash->array,idx,MA_HASHTBL_LINK*);
if (!hashcmp(hash,pos,key,length))
{
hash->current_record= idx;
return (pos->data);
}
if (flag)
{
flag=0; /* Reset flag */
if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
break; /* Wrong link */
}
}
while ((idx=pos->next) != NO_RECORD);
}
hash->current_record= NO_RECORD;
return(0);
}
/* Get next record with identical key */
/* Can only be called if previous calls was hash_search */
void *ma_hashtbl_next(MA_HASHTBL *hash,const uchar *key,uint length)
{
MA_HASHTBL_LINK *pos;
uint idx;
if (hash->current_record != NO_RECORD)
{
MA_HASHTBL_LINK *data=dynamic_element(&hash->array,0,MA_HASHTBL_LINK*);
for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next)
{
pos=data+idx;
if (!hashcmp(hash,pos,key,length))
{
hash->current_record= idx;
return pos->data;
}
}
hash->current_record=NO_RECORD;
}
return 0;
}
/* Change link from pos to new_link */
static void movelink(MA_HASHTBL_LINK *array,uint find,uint next_link,uint newlink)
{
MA_HASHTBL_LINK *old_link;
do
{
old_link=array+next_link;
}
while ((next_link=old_link->next) != find);
old_link->next= newlink;
return;
}
/* Compare a key in a record to a whole key. Return 0 if identical */
static int hashcmp(MA_HASHTBL *hash,MA_HASHTBL_LINK *pos,const uchar *key,uint length)
{
uint rec_keylength;
uchar *rec_key= (uchar*) hash_key(hash,pos->data,&rec_keylength,1);
return (length && length != rec_keylength) ||
memcmp(rec_key,key,rec_keylength);
}
/* Write a hash-key to the hash-index */
my_bool ma_hashtbl_insert(MA_HASHTBL *info,const uchar *record)
{
int flag;
uint halfbuff,hash_nr,first_index,idx;
uchar *ptr_to_rec= NULL,*ptr_to_rec2= NULL;
MA_HASHTBL_LINK *data,*empty,*gpos= NULL,*gpos2 = NULL,*pos;
LINT_INIT(gpos); LINT_INIT(gpos2);
LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
flag=0;
if (!(empty=(MA_HASHTBL_LINK*) ma_alloc_dynamic(&info->array)))
return(TRUE); /* No more memory */
info->current_record= NO_RECORD;
data=dynamic_element(&info->array,0,MA_HASHTBL_LINK*);
halfbuff= info->blength >> 1;
idx=first_index=info->records-halfbuff;
if (idx != info->records) /* If some records */
{
do
{
pos=data+idx;
hash_nr=rec_hashnr(info,pos->data);
if (flag == 0) /* First loop; Check if ok */
if (hash_mask(hash_nr,info->blength,info->records) != first_index)
break;
if (!(hash_nr & halfbuff))
{ /* Key will not move */
if (!(flag & LOWFIND))
{
if (flag & HIGHFIND)
{
flag=LOWFIND | HIGHFIND;
/* key shall be moved to the current empty position */
gpos=empty;
ptr_to_rec=pos->data;
empty=pos; /* This place is now free */
}
else
{
flag=LOWFIND | LOWUSED; /* key isn't changed */
gpos=pos;
ptr_to_rec=pos->data;
}
}
else
{
if (!(flag & LOWUSED))
{
/* Change link of previous LOW-key */
gpos->data=ptr_to_rec;
gpos->next=(uint) (pos-data);
flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
}
gpos=pos;
ptr_to_rec=pos->data;
}
}
else
{ /* key will be moved */
if (!(flag & HIGHFIND))
{
flag= (flag & LOWFIND) | HIGHFIND;
/* key shall be moved to the last (empty) position */
gpos2 = empty; empty=pos;
ptr_to_rec2=pos->data;
}
else
{
if (!(flag & HIGHUSED))
{
/* Change link of previous hash-key and save */
gpos2->data=ptr_to_rec2;
gpos2->next=(uint) (pos-data);
flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
}
gpos2=pos;
ptr_to_rec2=pos->data;
}
}
}
while ((idx=pos->next) != NO_RECORD);
if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
{
gpos->data=ptr_to_rec;
gpos->next=NO_RECORD;
}
if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
{
gpos2->data=ptr_to_rec2;
gpos2->next=NO_RECORD;
}
}
/* Check if we are at the empty position */
idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
pos=data+idx;
if (pos == empty)
{
pos->data=(uchar*) record;
pos->next=NO_RECORD;
}
else
{
/* Check if more records in same hash-nr family */
empty[0]=pos[0];
gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
if (pos == gpos)
{
pos->data=(uchar*) record;
pos->next=(uint) (empty - data);
}
else
{
pos->data=(uchar*) record;
pos->next=NO_RECORD;
movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
}
}
if (++info->records == info->blength)
info->blength+= info->blength;
return(0);
}
/******************************************************************************
** Remove one record from hash-table. The record with the same record
** ptr is removed.
** if there is a free-function it's called for record if found
******************************************************************************/
my_bool ma_hashtbl_delete(MA_HASHTBL *hash,uchar *record)
{
uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
MA_HASHTBL_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
if (!hash->records)
return(1);
blength=hash->blength;
data=dynamic_element(&hash->array,0,MA_HASHTBL_LINK*);
/* Search after record with key */
pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records);
gpos = 0;
while (pos->data != record)
{
gpos=pos;
if (pos->next == NO_RECORD)
return(1); /* Key not found */
pos=data+pos->next;
}
if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
hash->current_record= NO_RECORD;
lastpos=data+hash->records;
/* Remove link to record */
empty=pos; empty_index=(uint) (empty-data);
if (gpos)
gpos->next=pos->next; /* unlink current ptr */
else if (pos->next != NO_RECORD)
{
empty=data+(empty_index=pos->next);
pos->data=empty->data;
pos->next=empty->next;
}
if (empty == lastpos) /* last key at wrong pos or no next link */
goto exit;
/* Move the last key (lastpos) */
lastpos_hashnr=rec_hashnr(hash,lastpos->data);
/* pos is where lastpos should be */
pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
if (pos == empty) /* Move to empty position. */
{
empty[0]=lastpos[0];
goto exit;
}
pos_hashnr=rec_hashnr(hash,pos->data);
/* pos3 is where the pos should be */
pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records);
if (pos != pos3)
{ /* pos is on wrong posit */
empty[0]=pos[0]; /* Save it here */
pos[0]=lastpos[0]; /* This should be here */
movelink(data,(uint) (pos-data),(uint) (pos3-data),empty_index);
goto exit;
}
pos2= hash_mask(lastpos_hashnr,blength,hash->records+1);
if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1))
{ /* Identical key-positions */
if (pos2 != hash->records)
{
empty[0]=lastpos[0];
movelink(data,(uint) (lastpos-data),(uint) (pos-data),empty_index);
goto exit;
}
idx= (uint) (pos-data); /* Link pos->next after lastpos */
}
else idx= NO_RECORD; /* Different positions merge */
empty[0]=lastpos[0];
movelink(data,idx,empty_index,pos->next);
pos->next=empty_index;
exit:
ma_pop_dynamic(&hash->array);
if (hash->free)
(*hash->free)((uchar*) record);
return(0);
}
/*
Update keys when record has changed.
This is much more efficient than using a delete & insert.
*/
my_bool ma_hashtbl_update(MA_HASHTBL *hash,uchar *record,uchar *old_key,uint old_key_length)
{
uint idx,new_index,new_pos_index,blength,records,empty;
MA_HASHTBL_LINK org_link,*data,*previous,*pos;
data=dynamic_element(&hash->array,0,MA_HASHTBL_LINK*);
blength=hash->blength; records=hash->records;
/* Search after record with key */
idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ?
old_key_length :
hash->key_length)),
blength,records);
new_index=hash_mask(rec_hashnr(hash,record),blength,records);
if (idx == new_index)
return(0); /* Nothing to do (No record check) */
previous=0;
for (;;)
{
if ((pos= data+idx)->data == record)
break;
previous=pos;
if ((idx=pos->next) == NO_RECORD)
return(1); /* Not found in links */
}
hash->current_record= NO_RECORD;
org_link= *pos;
empty=idx;
/* Relink record from current chain */
if (!previous)
{
if (pos->next != NO_RECORD)
{
empty=pos->next;
*pos= data[pos->next];
}
}
else
previous->next=pos->next; /* unlink pos */
/* Move data to correct position */
pos=data+new_index;
new_pos_index=hash_rec_mask(hash,pos,blength,records);
if (new_index != new_pos_index)
{ /* Other record in wrong position */
data[empty] = *pos;
movelink(data,new_index,new_pos_index,empty);
org_link.next=NO_RECORD;
data[new_index]= org_link;
}
else
{ /* Link in chain at right position */
org_link.next=data[new_index].next;
data[empty]=org_link;
data[new_index].next=empty;
}
return(0);
}
uchar *ma_hashtbl_element(MA_HASHTBL *hash,uint idx)
{
if (idx < hash->records)
return dynamic_element(&hash->array,idx,MA_HASHTBL_LINK*)->data;
return 0;
}

87
vendor/MDBC/libmariadb/ma_init.c vendored Normal file
View File

@ -0,0 +1,87 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
#include <ma_global.h>
#include <ma_sys.h>
#include "mariadb_ctype.h"
#include <ma_string.h>
#include <mariadb_ctype.h>
#include <signal.h>
#ifdef _WIN32
#ifdef _MSC_VER
#include <locale.h>
#include <crtdbg.h>
#endif
static my_bool my_win_init(void);
#else
#define my_win_init()
#endif
my_bool ma_init_done=0;
/* Init ma_sys functions and ma_sys variabels */
void ma_init(void)
{
if (ma_init_done)
return;
ma_init_done=1;
{
#ifdef _WIN32
my_win_init();
#endif
return;
}
} /* ma_init */
void ma_end(int infoflag __attribute__((unused)))
{
#ifdef _WIN32
WSACleanup( );
#endif /* _WIN32 */
ma_init_done=0;
} /* ma_end */
#ifdef _WIN32
static my_bool my_win_init()
{
WORD VersionRequested;
int err;
WSADATA WsaData;
const unsigned int MajorVersion=2,
MinorVersion=2;
VersionRequested= MAKEWORD(MajorVersion, MinorVersion);
/* Load WinSock library */
if ((err= WSAStartup(VersionRequested, &WsaData)))
{
return 0;
}
/* make sure 2.2 or higher is supported */
if ((LOBYTE(WsaData.wVersion) * 10 + HIBYTE(WsaData.wVersion)) < 22)
{
WSACleanup();
return 1;
}
return 0;
}
#endif

224
vendor/MDBC/libmariadb/ma_io.c vendored Normal file
View File

@ -0,0 +1,224 @@
/*
Copyright (C) 2015 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA
*/
#include <ma_global.h>
#include <ma_sys.h>
#include <errmsg.h>
#include <mysql.h>
#include <mysql/client_plugin.h>
#include <mariadb/ma_io.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_REMOTEIO
struct st_mysql_client_plugin_REMOTEIO *rio_plugin= NULL;
#endif
/* {{{ ma_open */
MA_FILE *ma_open(const char *location, const char *mode, MYSQL *mysql)
{
int CodePage= -1;
FILE *fp= NULL;
MA_FILE *ma_file= NULL;
if (!location || !location[0])
return NULL;
#ifdef HAVE_REMOTEIO
if (strstr(location, "://"))
goto remote;
#endif
#ifdef _WIN32
if (mysql && mysql->charset)
CodePage= madb_get_windows_cp(mysql->charset->csname);
#endif
if (CodePage == -1)
{
if (!(fp= fopen(location, mode)))
{
return NULL;
}
}
#ifdef _WIN32
/* See CONC-44: we need to support non ascii filenames too, so we convert
current character set to wchar_t and try to open the file via _wsopen */
else
{
wchar_t *w_filename= NULL;
wchar_t *w_mode= NULL;
int len;
DWORD Length;
len= MultiByteToWideChar(CodePage, 0, location, (int)strlen(location), NULL, 0);
if (!len)
return NULL;
if (!(w_filename= (wchar_t *)calloc(1, (len + 1) * sizeof(wchar_t))))
{
my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return NULL;
}
Length= len;
len= MultiByteToWideChar(CodePage, 0, location, (int)strlen(location), w_filename, (int)Length);
if (!len)
{
/* todo: error handling */
free(w_filename);
return NULL;
}
len= (int)strlen(mode);
if (!(w_mode= (wchar_t *)calloc(1, (len + 1) * sizeof(wchar_t))))
{
my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
free(w_filename);
return NULL;
}
Length= len;
len= MultiByteToWideChar(CodePage, 0, mode, (int)strlen(mode), w_mode, (int)Length);
if (!len)
{
/* todo: error handling */
free(w_filename);
free(w_mode);
return NULL;
}
fp= _wfopen(w_filename, w_mode);
free(w_filename);
free(w_mode);
}
#endif
if (fp)
{
ma_file= (MA_FILE *)malloc(sizeof(MA_FILE));
if (!ma_file)
{
fclose(fp);
my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return NULL;
}
ma_file->type= MA_FILE_LOCAL;
ma_file->ptr= (void *)fp;
}
return ma_file;
#ifdef HAVE_REMOTEIO
remote:
/* check if plugin for remote io is available and try
* to open location */
{
MYSQL mysql;
if (rio_plugin ||(rio_plugin= (struct st_mysql_client_plugin_REMOTEIO *)
mysql_client_find_plugin(&mysql, NULL, MARIADB_CLIENT_REMOTEIO_PLUGIN)))
return rio_plugin->methods->mopen(location, mode);
return NULL;
}
#endif
}
/* }}} */
/* {{{ ma_close */
int ma_close(MA_FILE *file)
{
int rc;
if (!file)
return -1;
switch (file->type) {
case MA_FILE_LOCAL:
rc= fclose((FILE *)file->ptr);
free(file);
break;
#ifdef HAVE_REMOTEIO
case MA_FILE_REMOTE:
rc= rio_plugin->methods->mclose(file);
break;
#endif
default:
return -1;
}
return rc;
}
/* }}} */
/* {{{ ma_feof */
int ma_feof(MA_FILE *file)
{
if (!file)
return -1;
switch (file->type) {
case MA_FILE_LOCAL:
return feof((FILE *)file->ptr);
break;
#ifdef HAVE_REMOTEIO
case MA_FILE_REMOTE:
return rio_plugin->methods->mfeof(file);
break;
#endif
default:
return -1;
}
}
/* }}} */
/* {{{ ma_read */
size_t ma_read(void *ptr, size_t size, size_t nmemb, MA_FILE *file)
{
size_t s= 0;
if (!file)
return -1;
switch (file->type) {
case MA_FILE_LOCAL:
s= fread(ptr, size, nmemb, (FILE *)file->ptr);
return s;
break;
#ifdef HAVE_REMOTEIO
case MA_FILE_REMOTE:
return rio_plugin->methods->mread(ptr, size, nmemb, file);
break;
#endif
default:
return -1;
}
}
/* }}} */
/* {{{ ma_gets */
char *ma_gets(char *ptr, size_t size, MA_FILE *file)
{
if (!file)
return NULL;
switch (file->type) {
case MA_FILE_LOCAL:
return fgets(ptr, (int)size, (FILE *)file->ptr);
break;
#ifdef HAVE_REMOTEIO
case MA_FILE_REMOTE:
return rio_plugin->methods->mgets(ptr, size, file);
break;
#endif
default:
return NULL;
}
}
/* }}} */

114
vendor/MDBC/libmariadb/ma_list.c vendored Normal file
View File

@ -0,0 +1,114 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/*
Code for handling dubble-linked lists in C
*/
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_list.h>
/* Add a element to start of list */
LIST *list_add(LIST *root, LIST *element)
{
if (root)
{
if (root->prev) /* If add in mid of list */
root->prev->next= element;
element->prev=root->prev;
root->prev=element;
}
else
element->prev=0;
element->next=root;
return(element); /* New root */
}
LIST *list_delete(LIST *root, LIST *element)
{
if (element->prev)
element->prev->next=element->next;
else
root=element->next;
if (element->next)
element->next->prev=element->prev;
return root;
}
void list_free(LIST *root, unsigned int free_data)
{
LIST *next;
while (root)
{
next=root->next;
if (free_data)
free(root->data);
free(root);
root=next;
}
}
LIST *list_cons(void *data, LIST *list)
{
LIST *new_charset=(LIST*) malloc(sizeof(LIST));
if (!new_charset)
return 0;
new_charset->data=data;
return list_add(list,new_charset);
}
LIST *list_reverse(LIST *root)
{
LIST *last;
last=root;
while (root)
{
last=root;
root=root->next;
last->next=last->prev;
last->prev=root;
}
return last;
}
uint list_length(LIST *list)
{
uint count;
for (count=0 ; list ; list=list->next, count++) ;
return count;
}
int list_walk(LIST *list, list_walk_action action, gptr argument)
{
int error=0;
while (list)
{
if ((error = (*action)(list->data,argument)))
return error;
list= list_rest(list);
}
return 0;
}

70
vendor/MDBC/libmariadb/ma_ll2str.c vendored Normal file
View File

@ -0,0 +1,70 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016,2018 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
#include <ma_global.h>
#include "ma_string.h"
#include <ctype.h>
static char NEAR _dig_vec[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *ma_ll2str(long long val,char *dst,int radix)
{
char buffer[65];
register char *p;
long long_val;
if (radix < 0)
{
if (radix < -36 || radix > -2) return (char*) 0;
if (val < 0) {
*dst++ = '-';
val = 0ULL - val;
}
radix = -radix;
}
else
{
if (radix > 36 || radix < 2) return (char*) 0;
}
if (val == 0)
{
*dst++='0';
*dst='\0';
return dst;
}
p = &buffer[sizeof(buffer)-1];
*p = '\0';
while ((ulonglong) val > (ulonglong) LONG_MAX)
{
ulonglong quo=(ulonglong) val/(uint) radix;
uint rem= (uint) (val- quo* (uint) radix);
*--p = _dig_vec[rem];
val= quo;
}
long_val= (long) val;
while (long_val != 0)
{
long quo= long_val/radix;
*--p = _dig_vec[(uchar) (long_val - quo*radix)];
long_val= quo;
}
while ((*dst++ = *p++) != 0) ;
return dst-1;
}

265
vendor/MDBC/libmariadb/ma_loaddata.c vendored Normal file
View File

@ -0,0 +1,265 @@
/************************************************************************************
Copyright (C) 2000, 2011 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
Monty Program AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
Part of this code includes code from the PHP project which
is freely available from http://www.php.net
*************************************************************************************/
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2011 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
#include "ma_global.h"
#include <ma_sys.h>
#include <ma_string.h>
#include "errmsg.h"
#include "mysql.h"
#include <mariadb/ma_io.h>
#include <string.h>
#ifdef _WIN32
#include <share.h>
#endif
#include <ma_common.h>
typedef struct st_mysql_infile_info
{
MA_FILE *fp;
int error_no;
char error_msg[MYSQL_ERRMSG_SIZE + 1];
const char *filename;
} MYSQL_INFILE_INFO;
/* {{{ mysql_local_infile_init */
static
int mysql_local_infile_init(void **ptr, const char *filename, void *userdata)
{
MYSQL_INFILE_INFO *info;
MYSQL *mysql= (MYSQL *)userdata;
info = (MYSQL_INFILE_INFO *)malloc(sizeof(MYSQL_INFILE_INFO));
if (!info) {
return(1);
}
memset(info, 0, sizeof(MYSQL_INFILE_INFO));
*ptr = info;
info->filename = filename;
info->fp= ma_open(filename, "rb", mysql);
if (!info->fp)
{
/* error handling is done via mysql_local_infile_error function, so we
need to copy error to info */
if (mysql_errno(mysql) && !info->error_no)
{
info->error_no= mysql_errno(mysql);
ma_strmake(info->error_msg, mysql_error(mysql), MYSQL_ERRMSG_SIZE);
}
else
{
info->error_no = errno;
snprintf((char *)info->error_msg, sizeof(info->error_msg),
CER(CR_FILE_NOT_FOUND), filename, info->error_no);
}
return(1);
}
return(0);
}
/* }}} */
/* {{{ mysql_local_infile_read */
static
int mysql_local_infile_read(void *ptr, char * buf, unsigned int buf_len)
{
MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
size_t count;
count= ma_read((void *)buf, 1, (size_t)buf_len, info->fp);
if (count == (size_t)-1)
{
info->error_no = errno;
snprintf((char *)info->error_msg, sizeof(info->error_msg),
CER(CR_FILE_READ), info->filename, info->error_no);
}
return((int)count);
}
/* }}} */
/* {{{ mysql_local_infile_error */
static
int mysql_local_infile_error(void *ptr, char *error_buf, unsigned int error_buf_len)
{
MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
if (info) {
ma_strmake(error_buf, info->error_msg, error_buf_len);
return(info->error_no);
}
ma_strmake(error_buf, "Unknown error", error_buf_len);
return(CR_UNKNOWN_ERROR);
}
/* }}} */
/* {{{ mysql_local_infile_end */
static
void mysql_local_infile_end(void *ptr)
{
MYSQL_INFILE_INFO *info = (MYSQL_INFILE_INFO *)ptr;
if (info)
{
if (info->fp)
ma_close(info->fp);
free(ptr);
}
return;
}
/* }}} */
/* {{{ mysql_local_infile_default */
void mysql_set_local_infile_default(MYSQL *conn)
{
conn->options.local_infile_init = mysql_local_infile_init;
conn->options.local_infile_read = mysql_local_infile_read;
conn->options.local_infile_error = mysql_local_infile_error;
conn->options.local_infile_end = mysql_local_infile_end;
return;
}
/* }}} */
/* {{{ mysql_set_local_infile_handler */
void STDCALL mysql_set_local_infile_handler(MYSQL *conn,
int (*local_infile_init)(void **, const char *, void *),
int (*local_infile_read)(void *, char *, uint),
void (*local_infile_end)(void *),
int (*local_infile_error)(void *, char *, uint),
void *userdata)
{
conn->options.local_infile_init= local_infile_init;
conn->options.local_infile_read= local_infile_read;
conn->options.local_infile_end= local_infile_end;
conn->options.local_infile_error= local_infile_error;
conn->options.local_infile_userdata = userdata;
return;
}
/* }}} */
/* {{{ mysql_handle_local_infile */
my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename, my_bool can_local_infile)
{
unsigned int buflen= 4096;
int bufread;
unsigned char *buf= NULL;
void *info= NULL;
my_bool result= 1;
/* check if all callback functions exist */
if (!conn->options.local_infile_init || !conn->options.local_infile_end ||
!conn->options.local_infile_read || !conn->options.local_infile_error)
{
conn->options.local_infile_userdata= conn;
mysql_set_local_infile_default(conn);
}
if (!(conn->options.client_flag & CLIENT_LOCAL_FILES) ||
!can_local_infile)
{
my_set_error(conn, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, "Load data local infile forbidden");
/* write empty packet to server */
ma_net_write(&conn->net, (unsigned char *)"", 0);
ma_net_flush(&conn->net);
goto infile_error;
}
/* allocate buffer for reading data */
buf = (uchar *)malloc(buflen);
/* init handler: allocate read buffer and open file */
if (conn->options.local_infile_init(&info, filename,
conn->options.local_infile_userdata))
{
char tmp_buf[MYSQL_ERRMSG_SIZE];
int tmp_errno;
tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
ma_net_write(&conn->net, (unsigned char *)"", 0);
ma_net_flush(&conn->net);
goto infile_error;
}
/* read data */
while ((bufread= conn->options.local_infile_read(info, (char *)buf, buflen)) > 0)
{
if (ma_net_write(&conn->net, (unsigned char *)buf, bufread))
{
my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
goto infile_error;
}
}
/* send empty packet for eof */
if (ma_net_write(&conn->net, (unsigned char *)"", 0) ||
ma_net_flush(&conn->net))
{
my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL);
goto infile_error;
}
/* error during read occurred */
if (bufread < 0)
{
char tmp_buf[MYSQL_ERRMSG_SIZE];
int tmp_errno= conn->options.local_infile_error(info, tmp_buf, sizeof(tmp_buf));
my_set_error(conn, tmp_errno, SQLSTATE_UNKNOWN, tmp_buf);
goto infile_error;
}
result = 0;
infile_error:
conn->options.local_infile_end(info);
free(buf);
return(result);
}
/* }}} */

591
vendor/MDBC/libmariadb/ma_net.c vendored Normal file
View File

@ -0,0 +1,591 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2012-2016 SkySQL AB, MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/* Write and read of logical packets to/from socket
** Writes are cached into net_buffer_length big packets.
** Read packets are reallocated dynamically when reading big packets.
** Each logical packet has the following pre-info:
** 3 byte length & 1 byte package-number.
*/
#include <ma_global.h>
#include <mysql.h>
#include <ma_pvio.h>
#include <ma_sys.h>
#include <ma_string.h>
#include "mysql.h"
#include "ma_server_error.h"
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <ma_pvio.h>
#include <ma_common.h>
#ifndef _WIN32
#include <poll.h>
#endif
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
/* net_buffer_length and max_allowed_packet are defined in mysql.h
See bug conc-57
*/
#undef net_buffer_length
#undef max_allowed_packet
ulong max_allowed_packet=1024L * 1024L * 1024L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
ulong net_buffer_length= 8192; /* Default length. Enlarged if necessary */
#if !defined(_WIN32)
#include <sys/socket.h>
#else
#undef MYSQL_SERVER /* Win32 can't handle interrupts */
#endif
#if !defined(_WIN32) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#if !defined(alpha_linux_port)
#include <netinet/tcp.h>
#endif
#endif
/*
** Give error if a too big packet is found
** The server can change this with the -O switch, but because the client
** can't normally do this the client should have a bigger max-buffer.
*/
static int ma_net_write_buff(NET *net,const char *packet, size_t len);
/* Init with packet info */
int ma_net_init(NET *net, MARIADB_PVIO* pvio)
{
if (!(net->buff=(uchar*) malloc(net_buffer_length)))
return 1;
if (!net->extension)
return 1;
memset(net->buff, 0, net_buffer_length);
net->max_packet_size= MAX(net_buffer_length, max_allowed_packet);
net->buff_end=net->buff+(net->max_packet=net_buffer_length);
net->pvio = pvio;
net->error=0; net->return_status=0;
net->read_timeout=(uint) net_read_timeout; /* Timeout for read */
net->compress_pkt_nr= net->pkt_nr= 0;
net->write_pos=net->read_pos = net->buff;
net->last_error[0]= net->sqlstate[0] =0;
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
if (pvio != 0) /* If real connection */
{
ma_pvio_get_handle(pvio, &net->fd);
ma_pvio_blocking(pvio, 1, 0);
ma_pvio_fast_send(pvio);
}
return 0;
}
void ma_net_end(NET *net)
{
free(net->buff);
net->buff=0;
}
/* Realloc the packet buffer */
static my_bool net_realloc(NET *net, size_t length)
{
uchar *buff;
size_t pkt_length;
if (length >= net->max_packet_size)
{
net->error=1;
net->last_errno=ER_NET_PACKET_TOO_LARGE;
return(1);
}
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
/* reallocate buffer:
size= pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE */
if (!(buff=(uchar*) realloc(net->buff,
pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE)))
{
net->error=1;
return(1);
}
net->buff=net->write_pos=buff;
net->buff_end=buff+(net->max_packet=(unsigned long)pkt_length);
return(0);
}
/* Remove unwanted characters from connection */
void ma_net_clear(NET *net)
{
if (net->extension->multi_status > COM_MULTI_OFF)
return;
net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */
net->write_pos=net->buff;
return;
}
/* Flush write_buffer if not empty. */
int ma_net_flush(NET *net)
{
int error=0;
/* don't flush if pipelined query is in progress */
if (net->extension->multi_status > COM_MULTI_OFF)
return 0;
if (net->buff != net->write_pos)
{
error=ma_net_real_write(net,(char*) net->buff,
(size_t) (net->write_pos - net->buff));
net->write_pos=net->buff;
}
if (net->compress)
net->pkt_nr= net->compress_pkt_nr;
return(error);
}
/*****************************************************************************
** Write something to server/client buffer
*****************************************************************************/
/*
** Write a logical packet with packet header
** Format: Packet length (3 bytes), packet number(1 byte)
** When compression is used a 3 byte compression length is added
** NOTE: If compression is used the original package is destroyed!
*/
int ma_net_write(NET *net, const uchar *packet, size_t len)
{
uchar buff[NET_HEADER_SIZE];
while (len >= MAX_PACKET_LENGTH)
{
const ulong max_len= MAX_PACKET_LENGTH;
int3store(buff,max_len);
buff[3]= (uchar)net->pkt_nr++;
if (ma_net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
ma_net_write_buff(net, (char *)packet, max_len))
return 1;
packet+= max_len;
len-= max_len;
}
/* write last remaining packet, size can be zero */
int3store(buff, len);
buff[3]= (uchar)net->pkt_nr++;
if (ma_net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
ma_net_write_buff(net, (char *)packet, len))
return 1;
return 0;
}
int ma_net_write_command(NET *net, uchar command,
const char *packet, size_t len,
my_bool disable_flush)
{
uchar buff[NET_HEADER_SIZE+1];
size_t buff_size= NET_HEADER_SIZE + 1;
size_t length= 1 + len; /* 1 extra byte for command */
int rc;
buff[NET_HEADER_SIZE]= 0;
buff[4]=command;
if (length >= MAX_PACKET_LENGTH)
{
len= MAX_PACKET_LENGTH - 1;
do
{
int3store(buff, MAX_PACKET_LENGTH);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (ma_net_write_buff(net, (char *)buff, buff_size) ||
ma_net_write_buff(net, packet, len))
return(1);
packet+= len;
length-= MAX_PACKET_LENGTH;
len= MAX_PACKET_LENGTH;
buff_size= NET_HEADER_SIZE; /* don't send command for further packets */
} while (length >= MAX_PACKET_LENGTH);
len= length;
}
int3store(buff,length);
buff[3]= (net->compress) ? 0 :(uchar) (net->pkt_nr++);
rc= test (ma_net_write_buff(net,(char *)buff, buff_size) ||
ma_net_write_buff(net,packet,len));
if (!rc && !disable_flush)
return test(ma_net_flush(net));
return rc;
}
static int ma_net_write_buff(NET *net,const char *packet, size_t len)
{
size_t left_length;
if (!len)
return 0;
if (net->max_packet > MAX_PACKET_LENGTH &&
net->compress)
left_length= (size_t)(MAX_PACKET_LENGTH - (net->write_pos - net->buff));
else
left_length=(size_t) (net->buff_end - net->write_pos);
if (len > left_length)
{
if (net->write_pos != net->buff)
{
memcpy((char*) net->write_pos,packet,left_length);
if (ma_net_real_write(net,(char*) net->buff,
(size_t)(net->write_pos - net->buff) + left_length))
return 1;
packet+=left_length;
len-=left_length;
net->write_pos= net->buff;
}
if (net->compress)
{
/* uncompressed length is stored in 3 bytes,so
packet can't be > 0xFFFFFF */
left_length= MAX_PACKET_LENGTH;
while (len > left_length)
{
if (ma_net_real_write(net, packet, left_length))
return 1;
packet+= left_length;
len-= left_length;
}
}
if (len > net->max_packet)
return(test(ma_net_real_write(net, packet, len)));
}
memcpy((char*) net->write_pos,packet,len);
net->write_pos+=len;
return 0;
}
unsigned char *mysql_net_store_length(unsigned char *packet, size_t length);
/* Read and write using timeouts */
int ma_net_real_write(NET *net, const char *packet, size_t len)
{
ssize_t length;
char *pos,*end;
if (net->error == 2)
return(-1); /* socket can't be used */
net->reading_or_writing=2;
#ifdef HAVE_COMPRESS
if (net->compress)
{
size_t complen;
uchar *b;
uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
if (!(b=(uchar*) malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1)))
{
net->last_errno=ER_OUT_OF_RESOURCES;
net->error=2;
net->reading_or_writing=0;
return(1);
}
memcpy(b+header_length,packet,len);
if (_mariadb_compress((unsigned char*) b+header_length,&len,&complen))
{
complen=0;
}
int3store(&b[NET_HEADER_SIZE],complen);
int3store(b,len);
b[3]=(uchar) (net->compress_pkt_nr++);
len+= header_length;
packet= (char*) b;
}
#endif /* HAVE_COMPRESS */
pos=(char*) packet; end=pos+len;
while (pos != end)
{
if ((length=ma_pvio_write(net->pvio,(uchar *)pos,(size_t) (end-pos))) <= 0)
{
net->error=2; /* Close socket */
net->last_errno= ER_NET_ERROR_ON_WRITE;
net->reading_or_writing=0;
#ifdef HAVE_COMPRESS
if (net->compress)
free((char*) packet);
#endif
return(1);
}
pos+=length;
}
#ifdef HAVE_COMPRESS
if (net->compress)
free((char*) packet);
#endif
net->reading_or_writing=0;
return(((int) (pos != end)));
}
/*****************************************************************************
** Read something from server/clinet
*****************************************************************************/
static ulong ma_real_read(NET *net, size_t *complen)
{
uchar *pos;
ssize_t length;
uint i;
ulong len=packet_error;
size_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
NET_HEADER_SIZE);
*complen = 0;
net->reading_or_writing=1;
pos = net->buff + net->where_b; /* net->packet -4 */
for (i=0 ; i < 2 ; i++)
{
while (remain > 0)
{
/* First read is done with non blocking mode */
if ((length=ma_pvio_cache_read(net->pvio, pos,remain)) <= 0L)
{
len= packet_error;
net->error=2; /* Close socket */
goto end;
}
remain -= (ulong) length;
pos+= (ulong) length;
}
if (i == 0)
{ /* First parts is packet length */
ulong helping;
net->pkt_nr= net->buff[net->where_b + 3];
net->compress_pkt_nr= ++net->pkt_nr;
#ifdef HAVE_COMPRESS
if (net->compress)
{
/* complen is > 0 if package is really compressed */
*complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
}
#endif
len=uint3korr(net->buff+net->where_b);
if (!len)
goto end;
helping = max(len,(ulong)*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
if (net_realloc(net, helping))
{
len= packet_error; /* Return error */
goto end;
}
}
pos=net->buff + net->where_b;
remain = len;
}
}
end:
net->reading_or_writing=0;
return(len);
}
ulong ma_net_read(NET *net)
{
size_t len,complen;
#ifdef HAVE_COMPRESS
if (!net->compress)
{
#endif
len = ma_real_read (net,(size_t *)&complen);
if (len == MAX_PACKET_LENGTH)
{
/* multi packet read */
size_t length= 0;
ulong last_pos= net->where_b;
do
{
length+= len;
net->where_b+= (unsigned long)len;
len= ma_real_read(net, &complen);
} while (len == MAX_PACKET_LENGTH);
net->where_b= last_pos;
if (len != packet_error)
len+= length;
}
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
return (ulong)len;
#ifdef HAVE_COMPRESS
}
else
{
/*
compressed protocol:
--------------------------------------
packet_length 3
sequence_id 1
uncompressed_length 3
--------------------------------------
compressed data packet_length - 7
--------------------------------------
Another packet will follow if:
packet_length == MAX_PACKET_LENGTH
Last package will be identified by
- packet_length is zero (special case)
- packet_length < MAX_PACKET_LENGTH
*/
size_t packet_length,
buffer_length;
size_t current= 0, start= 0;
my_bool is_multi_packet= 0;
/* check if buffer is empty */
if (!net->remain_in_buf)
{
buffer_length= 0;
}
else
{
/* save position and restore \0 character */
buffer_length= net->buf_length;
current= net->buf_length - net->remain_in_buf;
start= current;
net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
}
for (;;)
{
if (buffer_length - current >= 4)
{
uchar *pos= net->buff + current;
packet_length= uint3korr(pos);
/* check if we have last package (special case: zero length) */
if (!packet_length)
{
current+= 4; /* length + sequence_id,
no more data will follow */
break;
}
if (packet_length + 4 <= buffer_length - current)
{
if (!is_multi_packet)
{
current= current + packet_length + 4;
}
else
{
/* remove packet_header */
memmove(net->buff + current,
net->buff + current + 4,
buffer_length - current);
buffer_length-= 4;
current+= packet_length;
}
/* do we have last packet ? */
if (packet_length != MAX_PACKET_LENGTH)
{
is_multi_packet= 0;
break;
}
else
is_multi_packet= 1;
if (start)
{
memmove(net->buff, net->buff + start,
buffer_length - start);
/* decrease buflen*/
buffer_length-= start;
start= 0;
}
continue;
}
}
if (start)
{
memmove(net->buff, net->buff + start, buffer_length - start);
/* decrease buflen and current */
current -= start;
buffer_length-= start;
start= 0;
}
net->where_b=(unsigned long)buffer_length;
if ((packet_length = ma_real_read(net,(size_t *)&complen)) == packet_error)
return packet_error;
if (_mariadb_uncompress((unsigned char*) net->buff + net->where_b, &packet_length, &complen))
{
net->error=2; /* caller will close socket */
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
break;
return packet_error;
}
buffer_length+= complen;
}
/* set values */
net->buf_length= (unsigned long)buffer_length;
net->remain_in_buf= (unsigned long)(buffer_length - current);
net->read_pos= net->buff + start + 4;
len= current - start - 4;
if (is_multi_packet)
len-= 4;
net->save_char= net->read_pos[len]; /* Must be saved */
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
#endif
return (ulong)len;
}
int net_add_multi_command(NET *net, uchar command, const uchar *packet,
size_t length)
{
if (net->extension->multi_status == COM_MULTI_OFF)
{
return(1);
}
/* don't increase packet number */
net->compress_pkt_nr= net->pkt_nr= 0;
return ma_net_write_command(net, command, (const char *)packet, length, 1);
}

162
vendor/MDBC/libmariadb/ma_password.c vendored Normal file
View File

@ -0,0 +1,162 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016,2018 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/* password checking routines */
/*****************************************************************************
The main idea is that no password are sent between client & server on
connection and that no password are saved in mysql in a decodable form.
On connection a random string is generated and sent to the client.
The client generates a new string with a random generator inited with
the hash values from the password and the sent string.
This 'check' string is sent to the server where it is compared with
a string generated from the stored hash_value of the password and the
random string.
The password is saved (in user.password) by using the PASSWORD() function in
mysql.
Example:
update user set password=PASSWORD("hello") where user="test"
This saves a hashed number as a string in the password field.
*****************************************************************************/
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_string.h>
#include <ma_sha1.h>
#include "mysql.h"
void ma_randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
{ /* For mysql 3.21.# */
#ifdef HAVE_purify
memset((char*) rand_st, 0m sizeof(*rand_st)); /* Avoid UMC warnings */
#endif
rand_st->max_value= 0x3FFFFFFFL;
rand_st->max_value_dbl=(double) rand_st->max_value;
rand_st->seed1=seed1%rand_st->max_value ;
rand_st->seed2=seed2%rand_st->max_value;
}
double 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);
}
void ma_hash_password(ulong *result, const char *password, size_t len)
{
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
ulong tmp;
const char *password_end= password + len;
for (; password < password_end; password++)
{
if (*password == ' ' || *password == '\t')
continue; /* skip space in password */
tmp= (ulong) (uchar) *password;
nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
nr2+=(nr2 << 8) ^ nr;
add+=tmp;
}
result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
result[1]=nr2 & (((ulong) 1L << 31) -1L);
return;
}
/*
* Generate a new message based on message and password
* The same thing is done in client and server and the results are checked.
*/
/* scramble for 4.1 servers
* Code based on php_nysqlnd_scramble function from PHP's mysqlnd extension,
* written by Andrey Hristov (andrey@php.net)
* License: PHP License 3.0
*/
void my_crypt(unsigned char *buffer, const unsigned char *s1, const unsigned char *s2, size_t len)
{
const unsigned char *s1_end= s1 + len;
while (s1 < s1_end) {
*buffer++= *s1++ ^ *s2++;
}
}
void ma_scramble_41(const unsigned char *buffer, const char *scramble, const char *password)
{
_MA_SHA1_CTX context;
unsigned char sha1[SHA1_MAX_LENGTH];
unsigned char sha2[SHA1_MAX_LENGTH];
/* Phase 1: hash password */
ma_SHA1Init(&context);
ma_SHA1Update(&context, (unsigned char *)password, strlen((char *)password));
ma_SHA1Final(sha1, &context);
/* Phase 2: hash sha1 */
ma_SHA1Init(&context);
ma_SHA1Update(&context, (unsigned char*)sha1, SHA1_MAX_LENGTH);
ma_SHA1Final(sha2, &context);
/* Phase 3: hash scramble + sha2 */
ma_SHA1Init(&context);
ma_SHA1Update(&context, (unsigned char *)scramble, SCRAMBLE_LENGTH);
ma_SHA1Update(&context, (unsigned char*)sha2, SHA1_MAX_LENGTH);
ma_SHA1Final((unsigned char *)buffer, &context);
/* let's crypt buffer now */
my_crypt((uchar *)buffer, (const unsigned char *)buffer, (const unsigned char *)sha1, SHA1_MAX_LENGTH);
}
/* }}} */
void ma_make_scrambled_password(char *to,const char *password)
{
ulong hash_res[2];
ma_hash_password(hash_res,password, strlen(password));
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
}
/*
* Generate a new message based on message and password
* The same thing is done in client and server and the results are checked.
*/
char *ma_scramble_323(char *to, const char *message, const char *password)
{
struct rand_struct rand_st;
ulong hash_pass[2], hash_message[2];
if (password && password[0])
{
char extra, *to_start=to;
const char *end_scramble323= message + SCRAMBLE_LENGTH_323;
ma_hash_password(hash_pass,password, (uint) strlen(password));
/* Don't use strlen, could be > SCRAMBLE_LENGTH_323 ! */
ma_hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
ma_randominit(&rand_st, hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
for (; message < end_scramble323; message++)
*to++= (char) (floor(rnd(&rand_st) * 31) + 64);
extra=(char) (floor(rnd(&rand_st) * 31));
while (to_start != to)
*(to_start++)^= extra;
}
*to= 0;
return to;
}

594
vendor/MDBC/libmariadb/ma_pvio.c vendored Normal file
View File

@ -0,0 +1,594 @@
/************************************************************************************
Copyright (C) 2015 MariaDB Corporation AB,
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
/* MariaDB Communication IO (PVIO) interface
PVIO is the interface for client server communication and replaces former vio
component of the client library.
PVIO support various protcols like sockets, pipes and shared memory, which are
implemented as plugins and can be extended therefore easily.
Interface function description:
ma_pvio_init allocates a new PVIO object which will be used
for the current connection
ma_pvio_close frees all resources of previously allocated PVIO object
and closes open connections
ma_pvio_read reads data from server
ma_pvio_write sends data to server
ma_pvio_set_timeout sets timeout for connection, read and write
ma_pvio_register_callback
register callback functions for read and write
*/
#include <ma_global.h>
#include <ma_sys.h>
#include <mysql.h>
#include <errmsg.h>
#include <mysql/client_plugin.h>
#include <string.h>
#include <ma_common.h>
#include <ma_pvio.h>
#include <mariadb_async.h>
#include <ma_context.h>
/* callback functions for read/write */
LIST *pvio_callback= NULL;
#define IS_BLOCKING_ERROR() \
IF_WIN(WSAGetLastError() != WSAEWOULDBLOCK, \
(errno != EAGAIN && errno != EINTR))
/* {{{ MARIADB_PVIO *ma_pvio_init */
MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo)
{
/* check connection type and load the required plugin.
* Currently we support the following pvio types:
* pvio_socket
* pvio_namedpipe
* pvio_sharedmed
*/
const char *pvio_plugins[] = {"pvio_socket", "pvio_npipe", "pvio_shmem"};
int type;
MARIADB_PVIO_PLUGIN *pvio_plugin;
MARIADB_PVIO *pvio= NULL;
switch (cinfo->type)
{
case PVIO_TYPE_UNIXSOCKET:
case PVIO_TYPE_SOCKET:
type= 0;
break;
#ifdef _WIN32
case PVIO_TYPE_NAMEDPIPE:
type= 1;
break;
case PVIO_TYPE_SHAREDMEM:
type= 2;
break;
#endif
default:
return NULL;
}
if (!(pvio_plugin= (MARIADB_PVIO_PLUGIN *)
mysql_client_find_plugin(cinfo->mysql,
pvio_plugins[type],
MARIADB_CLIENT_PVIO_PLUGIN)))
{
/* error already set in mysql_client_find_plugin */
return NULL;
}
/* coverity[var_deref_op] */
if (!(pvio= (MARIADB_PVIO *)calloc(1, sizeof(MARIADB_PVIO))))
{
my_set_error(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
return NULL;
}
/* register error routine and methods */
pvio->methods= pvio_plugin->methods;
pvio->set_error= my_set_error;
pvio->type= cinfo->type;
/* set timeout to connect timeout - after successful connect we will set
* correct values for read and write */
if (pvio->methods->set_timeout)
{
pvio->methods->set_timeout(pvio, PVIO_CONNECT_TIMEOUT, cinfo->mysql->options.connect_timeout);
pvio->methods->set_timeout(pvio, PVIO_READ_TIMEOUT, cinfo->mysql->options.connect_timeout);
pvio->methods->set_timeout(pvio, PVIO_WRITE_TIMEOUT, cinfo->mysql->options.connect_timeout);
}
if (!(pvio->cache= calloc(1, PVIO_READ_AHEAD_CACHE_SIZE)))
{
PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
free(pvio);
return NULL;
}
pvio->cache_size= 0;
pvio->cache_pos= pvio->cache;
return pvio;
}
/* }}} */
/* {{{ my_bool ma_pvio_is_alive */
my_bool ma_pvio_is_alive(MARIADB_PVIO *pvio)
{
if (!pvio)
return FALSE;
if (pvio->methods->is_alive)
return pvio->methods->is_alive(pvio);
return TRUE;
}
/* }}} */
/* {{{ int ma_pvio_fast_send */
int ma_pvio_fast_send(MARIADB_PVIO *pvio)
{
if (!pvio || !pvio->methods->fast_send)
return 1;
return pvio->methods->fast_send(pvio);
}
/* }}} */
/* {{{ int ma_pvio_keepalive */
int ma_pvio_keepalive(MARIADB_PVIO *pvio)
{
if (!pvio || !pvio->methods->keepalive)
return 1;
return pvio->methods->keepalive(pvio);
}
/* }}} */
/* {{{ my_bool ma_pvio_set_timeout */
my_bool ma_pvio_set_timeout(MARIADB_PVIO *pvio,
enum enum_pvio_timeout type,
int timeout)
{
if (!pvio)
return 1;
if (pvio->methods->set_timeout)
return pvio->methods->set_timeout(pvio, type, timeout);
return 1;
}
/* }}} */
/* {{{ size_t ma_pvio_read_async */
static size_t ma_pvio_read_async(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
{
ssize_t res= 0;
struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
int timeout= pvio->timeout[PVIO_READ_TIMEOUT];
if (!pvio->methods->async_read)
{
PVIO_SET_ERROR(pvio->mysql, CR_ASYNC_NOT_SUPPORTED, unknown_sqlstate, 0);
return -1;
}
for (;;)
{
if (pvio->methods->async_read)
res= pvio->methods->async_read(pvio, buffer, length);
if (res >= 0 || IS_BLOCKING_ERROR())
return res;
b->events_to_wait_for= MYSQL_WAIT_READ;
if (timeout >= 0)
{
b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT;
b->timeout_value= timeout;
}
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
if (b->events_occured & MYSQL_WAIT_TIMEOUT)
return -1;
}
}
/* }}} */
/* {{{ size_t ma_pvio_read */
ssize_t ma_pvio_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
{
ssize_t r= -1;
if (!pvio)
return -1;
if (IS_PVIO_ASYNC_ACTIVE(pvio))
{
r=
#if defined(HAVE_TLS) && !defined(HAVE_SCHANNEL)
(pvio->ctls) ? ma_tls_read_async(pvio, buffer, length) :
#endif
(ssize_t)ma_pvio_read_async(pvio, buffer, length);
goto end;
}
else
{
if (IS_PVIO_ASYNC(pvio))
{
/*
If switching from non-blocking to blocking API usage, set the socket
back to blocking mode.
*/
my_bool old_mode;
ma_pvio_blocking(pvio, TRUE, &old_mode);
}
}
/* secure connection */
#ifdef HAVE_TLS
if (pvio->ctls)
{
r= ma_pvio_tls_read(pvio->ctls, buffer, length);
goto end;
}
#endif
if (pvio->methods->read)
r= pvio->methods->read(pvio, buffer, length);
end:
if (pvio_callback)
{
void (*callback)(int mode, MYSQL *mysql, const uchar *buffer, size_t length);
LIST *p= pvio_callback;
while (p)
{
callback= p->data;
callback(0, pvio->mysql, buffer, r);
p= p->next;
}
}
return r;
}
/* }}} */
/* {{{ size_t ma_pvio_cache_read */
ssize_t ma_pvio_cache_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
{
ssize_t r;
if (!pvio)
return -1;
if (!pvio->cache)
return ma_pvio_read(pvio, buffer, length);
if (pvio->cache + pvio->cache_size > pvio->cache_pos)
{
ssize_t remaining = pvio->cache + pvio->cache_size - pvio->cache_pos;
assert(remaining > 0);
r= MIN((ssize_t)length, remaining);
memcpy(buffer, pvio->cache_pos, r);
pvio->cache_pos+= r;
}
else if (length >= PVIO_READ_AHEAD_CACHE_MIN_SIZE)
{
r= ma_pvio_read(pvio, buffer, length);
}
else
{
r= ma_pvio_read(pvio, pvio->cache, PVIO_READ_AHEAD_CACHE_SIZE);
if (r > 0)
{
if (length < (size_t)r)
{
pvio->cache_size= r;
pvio->cache_pos= pvio->cache + length;
r= length;
}
memcpy(buffer, pvio->cache, r);
}
}
return r;
}
/* }}} */
/* {{{ size_t ma_pvio_write_async */
static ssize_t ma_pvio_write_async(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
{
ssize_t res;
struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
int timeout= pvio->timeout[PVIO_WRITE_TIMEOUT];
for (;;)
{
res= pvio->methods->async_write(pvio, buffer, length);
if (res >= 0 || IS_BLOCKING_ERROR())
return res;
b->events_to_wait_for= MYSQL_WAIT_WRITE;
if (timeout >= 0)
{
b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT;
b->timeout_value= timeout;
}
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
if (b->events_occured & MYSQL_WAIT_TIMEOUT)
return -1;
}
}
/* }}} */
/* {{{ size_t ma_pvio_write */
ssize_t ma_pvio_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
{
ssize_t r= 0;
if (!pvio)
return -1;
if (IS_PVIO_ASYNC_ACTIVE(pvio))
{
r=
#if defined(HAVE_TLS) && !defined(HAVE_SCHANNEL)
(pvio->ctls) ? ma_tls_write_async(pvio, buffer, length) :
#endif
ma_pvio_write_async(pvio, buffer, length);
goto end;
}
else
{
if (IS_PVIO_ASYNC(pvio))
{
/*
If switching from non-blocking to blocking API usage, set the socket
back to blocking mode.
*/
my_bool old_mode;
ma_pvio_blocking(pvio, TRUE, &old_mode);
}
}
/* secure connection */
#ifdef HAVE_TLS
if (pvio->ctls)
{
r= ma_pvio_tls_write(pvio->ctls, buffer, length);
goto end;
}
#endif
if (pvio->methods->write)
r= pvio->methods->write(pvio, buffer, length);
end:
if (pvio_callback)
{
void (*callback)(int mode, MYSQL *mysql, const uchar *buffer, size_t length);
LIST *p= pvio_callback;
while (p)
{
callback= p->data;
callback(1, pvio->mysql, buffer, r);
p= p->next;
}
}
return r;
}
/* }}} */
/* {{{ void ma_pvio_close */
void ma_pvio_close(MARIADB_PVIO *pvio)
{
/* free internal structures and close connection */
if (pvio)
{
#ifdef HAVE_TLS
if (pvio->ctls)
{
ma_pvio_tls_close(pvio->ctls);
free(pvio->ctls);
}
#endif
if (pvio && pvio->methods->close)
pvio->methods->close(pvio);
if (pvio->cache)
free(pvio->cache);
free(pvio);
}
}
/* }}} */
/* {{{ my_bool ma_pvio_get_handle */
my_bool ma_pvio_get_handle(MARIADB_PVIO *pvio, void *handle)
{
if (pvio && pvio->methods->get_handle)
return pvio->methods->get_handle(pvio, handle);
return 1;
}
/* }}} */
/* {{{ ma_pvio_wait_async */
static my_bool
ma_pvio_wait_async(struct mysql_async_context *b, enum enum_pvio_io_event event,
int timeout)
{
switch (event)
{
case VIO_IO_EVENT_READ:
b->events_to_wait_for = MYSQL_WAIT_READ;
break;
case VIO_IO_EVENT_WRITE:
b->events_to_wait_for = MYSQL_WAIT_WRITE;
break;
case VIO_IO_EVENT_CONNECT:
b->events_to_wait_for = MYSQL_WAIT_WRITE | IF_WIN(0, MYSQL_WAIT_EXCEPT);
break;
}
if (timeout >= 0)
{
b->events_to_wait_for |= MYSQL_WAIT_TIMEOUT;
b->timeout_value= timeout;
}
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
return (b->events_occured & MYSQL_WAIT_TIMEOUT) ? 0 : 1;
}
/* }}} */
/* {{{ ma_pvio_wait_io_or_timeout */
int ma_pvio_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout)
{
if (pvio)
{
if (IS_PVIO_ASYNC_ACTIVE(pvio))
return ma_pvio_wait_async(pvio->mysql->options.extension->async_context,
(is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE,
timeout);
if (pvio && pvio->methods->wait_io_or_timeout)
return pvio->methods->wait_io_or_timeout(pvio, is_read, timeout);
}
return 1;
}
/* }}} */
/* {{{ my_bool ma_pvio_connect */
my_bool ma_pvio_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
{
if (pvio && pvio->methods->connect)
return pvio->methods->connect(pvio, cinfo);
return 1;
}
/* }}} */
/* {{{ my_bool ma_pvio_blocking */
my_bool ma_pvio_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode)
{
if (pvio && pvio->methods->blocking)
return pvio->methods->blocking(pvio, block, previous_mode) != 0;
return 1;
}
/* }}} */
/* {{{ my_bool ma_pvio_is_blocking */
my_bool ma_pvio_is_blocking(MARIADB_PVIO *pvio)
{
if (pvio && pvio->methods->is_blocking)
return pvio->methods->is_blocking(pvio);
return 1;
}
/* }}} */
/* {{{ ma_pvio_has_data */
my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *data_len)
{
/* check if we still have unread data in cache */
if (pvio && pvio->cache)
if (pvio->cache_pos > pvio->cache)
return test(pvio->cache_pos - pvio->cache);
if (pvio && pvio->methods->has_data)
return pvio->methods->has_data(pvio, data_len);
return 1;
}
/* }}} */
#ifdef HAVE_TLS
/* {{{ my_bool ma_pvio_start_ssl */
my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio)
{
if (!pvio || !pvio->mysql)
return 1;
CLEAR_CLIENT_ERROR(pvio->mysql);
if (!(pvio->ctls= ma_pvio_tls_init(pvio->mysql)))
{
return 1;
}
if (ma_pvio_tls_connect(pvio->ctls))
{
free(pvio->ctls);
pvio->ctls= NULL;
return 1;
}
/* default behaviour:
1. peer certificate verification
2. verify CN (requires option ssl_verify_check)
3. verrify finger print
*/
if ((pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
ma_pvio_tls_verify_server_cert(pvio->ctls))
return 1;
if (pvio->mysql->options.extension &&
((pvio->mysql->options.extension->tls_fp && pvio->mysql->options.extension->tls_fp[0]) ||
(pvio->mysql->options.extension->tls_fp_list && pvio->mysql->options.extension->tls_fp_list[0])))
{
if (ma_pvio_tls_check_fp(pvio->ctls,
pvio->mysql->options.extension->tls_fp,
pvio->mysql->options.extension->tls_fp_list))
return 1;
}
return 0;
}
/* }}} */
#endif
/* {{{ ma_pvio_register_callback */
int ma_pvio_register_callback(my_bool register_callback,
void (*callback_function)(int mode, MYSQL *mysql, const uchar *buffer, size_t length))
{
LIST *list;
if (!callback_function)
return 1;
/* plugin will unregister in it's deinit function */
if (register_callback)
{
list= (LIST *)malloc(sizeof(LIST));
list->data= (void *)callback_function;
pvio_callback= list_add(pvio_callback, list);
}
else /* unregister callback function */
{
LIST *p= pvio_callback;
while (p)
{
if (p->data == callback_function)
{
list_delete(pvio_callback, p);
break;
}
p= p->next;
}
}
return 0;
}
/* }}} */

326
vendor/MDBC/libmariadb/ma_sha1.c vendored Normal file
View File

@ -0,0 +1,326 @@
/****************************************************************************
Copyright (C) 2012 Monty Program AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*****************************************************************************/
/* This code came from the PHP project, initially written by
Stefan Esser */
#include "ma_global.h"
#include "string.h"
/* This code is heavily based on the PHP md5 implementation */
#include "ma_sha1.h"
static void ma_SHA1Transform(uint32[5], const unsigned char[64]);
static void ma_SHA1Encode(unsigned char *, uint32 *, unsigned int);
static void ma_SHA1Decode(uint32 *, const unsigned char *, unsigned int);
static unsigned char PADDING[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic SHA1 functions.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((x) ^ (y) ^ (z))
#define H(x, y, z) (((x) & (y)) | ((z) & ((x) | (y))))
#define I(x, y, z) ((x) ^ (y) ^ (z))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* W[i]
*/
#define W(i) ( tmp=x[(i-3)&15]^x[(i-8)&15]^x[(i-14)&15]^x[i&15], \
(x[i&15]=ROTATE_LEFT(tmp, 1)) )
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
*/
#define FF(a, b, c, d, e, w) { \
(e) += F ((b), (c), (d)) + (w) + (uint32)(0x5A827999); \
(e) += ROTATE_LEFT ((a), 5); \
(b) = ROTATE_LEFT((b), 30); \
}
#define GG(a, b, c, d, e, w) { \
(e) += G ((b), (c), (d)) + (w) + (uint32)(0x6ED9EBA1); \
(e) += ROTATE_LEFT ((a), 5); \
(b) = ROTATE_LEFT((b), 30); \
}
#define HH(a, b, c, d, e, w) { \
(e) += H ((b), (c), (d)) + (w) + (uint32)(0x8F1BBCDC); \
(e) += ROTATE_LEFT ((a), 5); \
(b) = ROTATE_LEFT((b), 30); \
}
#define II(a, b, c, d, e, w) { \
(e) += I ((b), (c), (d)) + (w) + (uint32)(0xCA62C1D6); \
(e) += ROTATE_LEFT ((a), 5); \
(b) = ROTATE_LEFT((b), 30); \
}
/* {{{ ma_SHA1Init
* SHA1 initialization. Begins an SHA1 operation, writing a new context.
*/
void ma_SHA1Init(_MA_SHA1_CTX * context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
context->state[4] = 0xc3d2e1f0;
}
/* }}} */
/* {{{ ma_SHA1Update
SHA1 block update operation. Continues an SHA1 message-digest
operation, processing another message block, and updating the
context.
*/
void ma_SHA1Update(_MA_SHA1_CTX * context, const unsigned char *input,
size_t inputLen)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((uint32) inputLen << 3))
< ((uint32) inputLen << 3))
context->count[1]++;
context->count[1] += ((uint32) inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
memcpy
((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen);
ma_SHA1Transform(context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
ma_SHA1Transform(context->state, &input[i]);
index = 0;
} else
i = 0;
/* Buffer remaining input */
memcpy
((unsigned char*) & context->buffer[index], (unsigned char*) & input[i],
inputLen - i);
}
/* }}} */
/* {{{ ma_SHA1Final
SHA1 finalization. Ends an SHA1 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void ma_SHA1Final(unsigned char digest[20], _MA_SHA1_CTX * context)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
bits[7] = context->count[0] & 0xFF;
bits[6] = (context->count[0] >> 8) & 0xFF;
bits[5] = (context->count[0] >> 16) & 0xFF;
bits[4] = (context->count[0] >> 24) & 0xFF;
bits[3] = context->count[1] & 0xFF;
bits[2] = (context->count[1] >> 8) & 0xFF;
bits[1] = (context->count[1] >> 16) & 0xFF;
bits[0] = (context->count[1] >> 24) & 0xFF;
/* Pad out to 56 mod 64.
*/
index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
ma_SHA1Update(context, PADDING, padLen);
/* Append length (before padding) */
ma_SHA1Update(context, bits, 8);
/* Store state in digest */
ma_SHA1Encode(digest, context->state, 20);
/* Zeroize sensitive information.
*/
memset((unsigned char*) context, 0, sizeof(*context));
}
/* }}} */
/* {{{ ma_SHA1Transform
* SHA1 basic transformation. Transforms state based on block.
*/
static void ma_SHA1Transform(uint32 state[5], const unsigned char block[64])
{
uint32 a = state[0], b = state[1], c = state[2];
uint32 d = state[3], e = state[4], x[16], tmp;
ma_SHA1Decode(x, block, 64);
/* Round 1 */
FF(a, b, c, d, e, x[0]); /* 1 */
FF(e, a, b, c, d, x[1]); /* 2 */
FF(d, e, a, b, c, x[2]); /* 3 */
FF(c, d, e, a, b, x[3]); /* 4 */
FF(b, c, d, e, a, x[4]); /* 5 */
FF(a, b, c, d, e, x[5]); /* 6 */
FF(e, a, b, c, d, x[6]); /* 7 */
FF(d, e, a, b, c, x[7]); /* 8 */
FF(c, d, e, a, b, x[8]); /* 9 */
FF(b, c, d, e, a, x[9]); /* 10 */
FF(a, b, c, d, e, x[10]); /* 11 */
FF(e, a, b, c, d, x[11]); /* 12 */
FF(d, e, a, b, c, x[12]); /* 13 */
FF(c, d, e, a, b, x[13]); /* 14 */
FF(b, c, d, e, a, x[14]); /* 15 */
FF(a, b, c, d, e, x[15]); /* 16 */
FF(e, a, b, c, d, W(16)); /* 17 */
FF(d, e, a, b, c, W(17)); /* 18 */
FF(c, d, e, a, b, W(18)); /* 19 */
FF(b, c, d, e, a, W(19)); /* 20 */
/* Round 2 */
GG(a, b, c, d, e, W(20)); /* 21 */
GG(e, a, b, c, d, W(21)); /* 22 */
GG(d, e, a, b, c, W(22)); /* 23 */
GG(c, d, e, a, b, W(23)); /* 24 */
GG(b, c, d, e, a, W(24)); /* 25 */
GG(a, b, c, d, e, W(25)); /* 26 */
GG(e, a, b, c, d, W(26)); /* 27 */
GG(d, e, a, b, c, W(27)); /* 28 */
GG(c, d, e, a, b, W(28)); /* 29 */
GG(b, c, d, e, a, W(29)); /* 30 */
GG(a, b, c, d, e, W(30)); /* 31 */
GG(e, a, b, c, d, W(31)); /* 32 */
GG(d, e, a, b, c, W(32)); /* 33 */
GG(c, d, e, a, b, W(33)); /* 34 */
GG(b, c, d, e, a, W(34)); /* 35 */
GG(a, b, c, d, e, W(35)); /* 36 */
GG(e, a, b, c, d, W(36)); /* 37 */
GG(d, e, a, b, c, W(37)); /* 38 */
GG(c, d, e, a, b, W(38)); /* 39 */
GG(b, c, d, e, a, W(39)); /* 40 */
/* Round 3 */
HH(a, b, c, d, e, W(40)); /* 41 */
HH(e, a, b, c, d, W(41)); /* 42 */
HH(d, e, a, b, c, W(42)); /* 43 */
HH(c, d, e, a, b, W(43)); /* 44 */
HH(b, c, d, e, a, W(44)); /* 45 */
HH(a, b, c, d, e, W(45)); /* 46 */
HH(e, a, b, c, d, W(46)); /* 47 */
HH(d, e, a, b, c, W(47)); /* 48 */
HH(c, d, e, a, b, W(48)); /* 49 */
HH(b, c, d, e, a, W(49)); /* 50 */
HH(a, b, c, d, e, W(50)); /* 51 */
HH(e, a, b, c, d, W(51)); /* 52 */
HH(d, e, a, b, c, W(52)); /* 53 */
HH(c, d, e, a, b, W(53)); /* 54 */
HH(b, c, d, e, a, W(54)); /* 55 */
HH(a, b, c, d, e, W(55)); /* 56 */
HH(e, a, b, c, d, W(56)); /* 57 */
HH(d, e, a, b, c, W(57)); /* 58 */
HH(c, d, e, a, b, W(58)); /* 59 */
HH(b, c, d, e, a, W(59)); /* 60 */
/* Round 4 */
II(a, b, c, d, e, W(60)); /* 61 */
II(e, a, b, c, d, W(61)); /* 62 */
II(d, e, a, b, c, W(62)); /* 63 */
II(c, d, e, a, b, W(63)); /* 64 */
II(b, c, d, e, a, W(64)); /* 65 */
II(a, b, c, d, e, W(65)); /* 66 */
II(e, a, b, c, d, W(66)); /* 67 */
II(d, e, a, b, c, W(67)); /* 68 */
II(c, d, e, a, b, W(68)); /* 69 */
II(b, c, d, e, a, W(69)); /* 70 */
II(a, b, c, d, e, W(70)); /* 71 */
II(e, a, b, c, d, W(71)); /* 72 */
II(d, e, a, b, c, W(72)); /* 73 */
II(c, d, e, a, b, W(73)); /* 74 */
II(b, c, d, e, a, W(74)); /* 75 */
II(a, b, c, d, e, W(75)); /* 76 */
II(e, a, b, c, d, W(76)); /* 77 */
II(d, e, a, b, c, W(77)); /* 78 */
II(c, d, e, a, b, W(78)); /* 79 */
II(b, c, d, e, a, W(79)); /* 80 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Zeroize sensitive information. */
memset((unsigned char*) x, 0, sizeof(x));
}
/* }}} */
/* {{{ ma_SHA1Encode
Encodes input (uint32) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void ma_SHA1Encode(unsigned char *output, uint32 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char) ((input[i] >> 24) & 0xff);
output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff);
output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff);
output[j + 3] = (unsigned char) (input[i] & 0xff);
}
}
/* }}} */
/* {{{ ma_SHA1Decode
Decodes input (unsigned char) into output (uint32). Assumes len is
a multiple of 4.
*/
static void ma_SHA1Decode(uint32 *output, const unsigned char * input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint32) input[j + 3]) | (((uint32) input[j + 2]) << 8) |
(((uint32) input[j + 1]) << 16) | (((uint32) input[j]) << 24);
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/

1362
vendor/MDBC/libmariadb/ma_stmt_codec.c vendored Normal file

File diff suppressed because it is too large Load Diff

163
vendor/MDBC/libmariadb/ma_string.c vendored Normal file
View File

@ -0,0 +1,163 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
/*
Code for handling strings which can grow dynamically.
Copyright Monty Program KB.
By monty.
*/
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_string.h>
my_bool ma_init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
size_t init_alloc, size_t alloc_increment)
{
uint length;
if (!alloc_increment)
alloc_increment=128;
length=1;
if (init_str && (length= (uint) strlen(init_str)+1) < init_alloc)
init_alloc=((length+alloc_increment-1)/alloc_increment)*alloc_increment;
if (!init_alloc)
init_alloc=alloc_increment;
if (!(str->str=(char*) malloc(init_alloc)))
return(TRUE);
str->length=length-1;
if (init_str)
memcpy(str->str,init_str,length);
str->max_length=init_alloc;
str->alloc_increment=alloc_increment;
return(FALSE);
}
my_bool ma_dynstr_set(DYNAMIC_STRING *str, const char *init_str)
{
uint length;
if (init_str && (length= (uint) strlen(init_str)+1) > str->max_length)
{
str->max_length=((length+str->alloc_increment-1)/str->alloc_increment)*
str->alloc_increment;
if (!str->max_length)
str->max_length=str->alloc_increment;
if (!(str->str=(char*) realloc(str->str,str->max_length)))
return(TRUE);
}
if (init_str)
{
str->length=length-1;
memcpy(str->str,init_str,length);
}
else
str->length=0;
return(FALSE);
}
my_bool ma_dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size)
{
if (!additional_size) return(FALSE);
if (str->length + additional_size > str->max_length)
{
str->max_length=((str->length + additional_size+str->alloc_increment-1)/
str->alloc_increment)*str->alloc_increment;
if (!(str->str=(char*) realloc(str->str,str->max_length)))
return(TRUE);
}
return(FALSE);
}
my_bool ma_dynstr_append(DYNAMIC_STRING *str, const char *append)
{
return ma_dynstr_append_mem(str,append,strlen(append));
}
my_bool ma_dynstr_append_quoted(DYNAMIC_STRING *str,
const char *append, size_t len,
char quote)
{
size_t additional= str->alloc_increment;
size_t lim= additional;
uint i;
if (ma_dynstr_realloc(str, len + additional + 2))
return TRUE;
str->str[str->length++]= quote;
for (i= 0; i < len; i++)
{
register char c= append[i];
if (c == quote || c == '\\')
{
if (!lim)
{
if (ma_dynstr_realloc(str, additional))
return TRUE;
lim= additional;
}
lim--;
str->str[str->length++]= '\\';
}
str->str[str->length++]= c;
}
str->str[str->length++]= quote;
return FALSE;
}
my_bool ma_dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
size_t length)
{
char *new_ptr;
if (str->length+length >= str->max_length)
{
size_t new_length=(str->length+length+str->alloc_increment)/
str->alloc_increment;
new_length*=str->alloc_increment;
if (!(new_ptr=(char*) realloc(str->str,new_length)))
return TRUE;
str->str=new_ptr;
str->max_length=new_length;
}
memcpy(str->str + str->length,append,length);
str->length+=length;
str->str[str->length]=0; /* Safety for C programs */
return FALSE;
}
void ma_dynstr_free(DYNAMIC_STRING *str)
{
if (str->str)
{
free(str->str);
str->str=0;
}
}
char *ma_strmake(register char *dst, register const char *src, size_t length)
{
while (length--)
if (! (*dst++ = *src++))
return dst-1;
*dst=0;
return dst;
}

65
vendor/MDBC/libmariadb/ma_time.c vendored Normal file
View File

@ -0,0 +1,65 @@
/****************************************************************************
Copyright (C) 2013 Monty Program AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
Part of this code includes code from the PHP project which
is freely available from http://www.php.net
*****************************************************************************/
#include <ma_global.h>
#include <mysql.h>
#include <stdio.h>
size_t mariadb_time_to_string(const MYSQL_TIME *tm, char *time_str, size_t len,
unsigned int digits)
{
size_t length;
if (!time_str || !len)
return 0;
if (digits == AUTO_SEC_PART_DIGITS)
digits= (tm->second_part) ? SEC_PART_DIGITS : 0;
switch(tm->time_type) {
case MYSQL_TIMESTAMP_DATE:
length= snprintf(time_str, len, "%04u-%02u-%02u", tm->year, tm->month, tm->day);
digits= 0;
break;
case MYSQL_TIMESTAMP_DATETIME:
length= snprintf(time_str, len, "%04u-%02u-%02u %02u:%02u:%02u",
tm->year, tm->month, tm->day, tm->hour, tm->minute, tm->second);
break;
case MYSQL_TIMESTAMP_TIME:
length= snprintf(time_str, len, "%s%02u:%02u:%02u",
(tm->neg ? "-" : ""), tm->hour, tm->minute, tm->second);
break;
default:
time_str[0]= '\0';
return 0;
break;
}
if (digits && (len < length))
{
char helper[16];
snprintf(helper, 16, ".%%0%du", digits);
length+= snprintf(time_str + length, len - length, helper, digits);
}
return length;
}

232
vendor/MDBC/libmariadb/ma_tls.c vendored Normal file
View File

@ -0,0 +1,232 @@
/************************************************************************************
Copyright (C) 2014 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
/*
* this is the abstraction layer for communication via SSL.
* The following SSL libraries/variants are currently supported:
* - openssl
* - gnutls
* - schannel (windows only)
*
* Different SSL variants are implemented as plugins
* On Windows schannel is implemented as (standard)
* built-in plugin.
*/
#ifdef HAVE_TLS
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_common.h>
#include <string.h>
#include <errmsg.h>
#include <ma_pvio.h>
#include <ma_tls.h>
#include <mysql/client_plugin.h>
#include <mariadb/ma_io.h>
#ifdef HAVE_NONBLOCK
#include <mariadb_async.h>
#include <ma_context.h>
#endif
/* Errors should be handled via pvio callback function */
my_bool ma_tls_initialized= FALSE;
unsigned int mariadb_deinitialize_ssl= 1;
const char *tls_protocol_version[]=
{"SSLv3", "TLSv1.0", "TLSv1.1", "TLSv1.2", "TLSv1.3", "Unknown"};
MARIADB_TLS *ma_pvio_tls_init(MYSQL *mysql)
{
MARIADB_TLS *ctls= NULL;
if (!ma_tls_initialized)
ma_tls_start(mysql->net.last_error, MYSQL_ERRMSG_SIZE);
if (!(ctls= (MARIADB_TLS *)calloc(1, sizeof(MARIADB_TLS))))
{
return NULL;
}
/* register error routine and methods */
ctls->pvio= mysql->net.pvio;
if (!(ctls->ssl= ma_tls_init(mysql)))
{
free(ctls);
ctls= NULL;
}
return ctls;
}
my_bool ma_pvio_tls_connect(MARIADB_TLS *ctls)
{
my_bool rc;
if ((rc= ma_tls_connect(ctls)))
ma_tls_close(ctls);
return rc;
}
ssize_t ma_pvio_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
return ma_tls_read(ctls, buffer, length);
}
ssize_t ma_pvio_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
return ma_tls_write(ctls, buffer, length);
}
my_bool ma_pvio_tls_close(MARIADB_TLS *ctls)
{
return ma_tls_close(ctls);
}
int ma_pvio_tls_verify_server_cert(MARIADB_TLS *ctls)
{
return ma_tls_verify_server_cert(ctls);
}
const char *ma_pvio_tls_cipher(MARIADB_TLS *ctls)
{
return ma_tls_get_cipher(ctls);
}
void ma_pvio_tls_end()
{
ma_tls_end();
}
int ma_pvio_tls_get_protocol_version_id(MARIADB_TLS *ctls)
{
return ma_tls_get_protocol_version(ctls);
}
const char *ma_pvio_tls_get_protocol_version(MARIADB_TLS *ctls)
{
int version;
version= ma_tls_get_protocol_version(ctls);
if (version < 0 || version > PROTOCOL_MAX)
return tls_protocol_version[PROTOCOL_UNKNOWN];
return tls_protocol_version[version];
}
static signed char ma_hex2int(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return 10 + c - 'A';
if (c >= 'a' && c <= 'f')
return 10 + c - 'a';
return -1;
}
static my_bool ma_pvio_tls_compare_fp(const char *cert_fp,
unsigned int cert_fp_len,
const char *fp, unsigned int fp_len)
{
char *p= (char *)fp,
*c;
/* check length */
if (cert_fp_len != 20)
return 1;
/* We support two formats:
2 digits hex numbers, separated by colons (length=59)
20 * 2 digits hex numbers without separators (length = 40)
*/
if (fp_len != (strchr(fp, ':') ? 59 : 40))
return 1;
for(c= (char *)cert_fp; c < cert_fp + cert_fp_len; c++)
{
signed char d1, d2;
if (*p == ':')
p++;
if (p - fp > (int)fp_len -1)
return 1;
if ((d1 = ma_hex2int(*p)) == - 1 ||
(d2 = ma_hex2int(*(p+1))) == -1 ||
(char)(d1 * 16 + d2) != *c)
return 1;
p+= 2;
}
return 0;
}
my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_list)
{
unsigned int cert_fp_len= 64;
char *cert_fp= NULL;
my_bool rc=1;
MYSQL *mysql= ctls->pvio->mysql;
cert_fp= (char *)malloc(cert_fp_len);
if ((cert_fp_len= ma_tls_get_finger_print(ctls, cert_fp, cert_fp_len)) < 1)
goto end;
if (fp)
rc= ma_pvio_tls_compare_fp(cert_fp, cert_fp_len, fp, (unsigned int)strlen(fp));
else if (fp_list)
{
MA_FILE *fp;
char buff[255];
if (!(fp = ma_open(fp_list, "r", mysql)))
goto end;
while (ma_gets(buff, sizeof(buff)-1, fp))
{
/* remove trailing new line character */
char *pos= strchr(buff, '\r');
if (!pos)
pos= strchr(buff, '\n');
if (pos)
*pos= '\0';
if (!ma_pvio_tls_compare_fp(cert_fp, cert_fp_len, buff, (unsigned int)strlen(buff)))
{
/* finger print is valid: close file and exit */
ma_close(fp);
rc= 0;
goto end;
}
}
/* No finger print matched - close file and return error */
ma_close(fp);
}
end:
if (cert_fp)
free(cert_fp);
if (rc)
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Fingerprint verification of server certificate failed");
}
return rc;
}
#endif /* HAVE_TLS */

1946
vendor/MDBC/libmariadb/mariadb_async.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2016 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA */
#include <ma_global.h>
#include <ma_sys.h>
// #include "mysys_err.h"
#include <mariadb_ctype.h>
#include <ma_string.h>
MARIADB_CHARSET_INFO *ma_default_charset_info; /* will be set in mysql_server_init */
MARIADB_CHARSET_INFO *ma_charset_bin= (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[32];
MARIADB_CHARSET_INFO *ma_charset_latin1= (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[5];
MARIADB_CHARSET_INFO *ma_charset_utf8_general_ci= (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[21];
MARIADB_CHARSET_INFO *ma_charset_utf16le_general_ci= (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[68];
MARIADB_CHARSET_INFO * STDCALL mysql_get_charset_by_nr(uint cs_number)
{
int i= 0;
while (mariadb_compiled_charsets[i].nr && cs_number != mariadb_compiled_charsets[i].nr)
i++;
return (mariadb_compiled_charsets[i].nr) ? (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[i] : NULL;
}
my_bool set_default_charset(uint cs, myf flags __attribute__((unused)))
{
MARIADB_CHARSET_INFO *new_charset;
new_charset = mysql_get_charset_by_nr(cs);
if (!new_charset)
{
return(TRUE); /* error */
}
ma_default_charset_info = new_charset;
return(FALSE);
}
MARIADB_CHARSET_INFO * STDCALL mysql_get_charset_by_name(const char *cs_name)
{
int i= 0;
while (mariadb_compiled_charsets[i].nr && strcmp(cs_name, mariadb_compiled_charsets[i].csname) != 0)
i++;
return (mariadb_compiled_charsets[i].nr) ? (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[i] : NULL;
}
my_bool set_default_charset_by_name(const char *cs_name, myf flags __attribute__((unused)))
{
MARIADB_CHARSET_INFO *new_charset;
new_charset = mysql_get_charset_by_name(cs_name);
if (!new_charset)
{
return(TRUE); /* error */
}
ma_default_charset_info = new_charset;
return(FALSE);
}

4368
vendor/MDBC/libmariadb/mariadb_dyncol.c vendored Normal file

File diff suppressed because it is too large Load Diff

4522
vendor/MDBC/libmariadb/mariadb_lib.c vendored Normal file

File diff suppressed because it is too large Load Diff

513
vendor/MDBC/libmariadb/mariadb_rpl.c vendored Normal file
View File

@ -0,0 +1,513 @@
/************************************************************************************
Copyright (C) 2018 MariaDB Corpoeation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include <ma_global.h>
#include <ma_sys.h>
#include <mysql.h>
#include <errmsg.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <zlib.h>
#include <mariadb_rpl.h>
static int rpl_alloc_string(MARIADB_RPL_EVENT *event,
MARIADB_STRING *s,
unsigned char *buffer,
size_t len)
{
if (!(s->str= ma_alloc_root(&event->memroot, len)))
return 1;
memcpy(s->str, buffer, len);
s->length= len;
return 0;
}
MARIADB_RPL * STDCALL mariadb_rpl_init_ex(MYSQL *mysql, unsigned int version)
{
MARIADB_RPL *rpl;
if (version < MARIADB_RPL_REQUIRED_VERSION ||
version > MARIADB_RPL_VERSION)
{
my_set_error(mysql, CR_VERSION_MISMATCH, SQLSTATE_UNKNOWN, 0, version,
MARIADB_RPL_VERSION, MARIADB_RPL_REQUIRED_VERSION);
return 0;
}
if (!mysql)
return NULL;
if (!(rpl= (MARIADB_RPL *)calloc(1, sizeof(MARIADB_RPL))))
{
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return 0;
}
rpl->version= version;
rpl->mysql= mysql;
return rpl;
}
void STDCALL mariadb_free_rpl_event(MARIADB_RPL_EVENT *event)
{
if (event)
{
ma_free_root(&event->memroot, MYF(0));
free(event);
}
}
int STDCALL mariadb_rpl_open(MARIADB_RPL *rpl)
{
unsigned char *ptr, *buf;
if (!rpl || !rpl->mysql)
return 1;
/* COM_BINLOG_DUMP:
Ofs Len Data
0 1 COM_BINLOG_DUMP
1 4 position
5 2 flags
7 4 server id
11 * filename
* = filename length
*/
ptr= buf=
#ifdef WIN32
(unsigned char *)_alloca(rpl->filename_length + 11);
#else
(unsigned char *)alloca(rpl->filename_length + 11);
#endif
int4store(ptr, (unsigned int)rpl->start_position);
ptr+= 4;
int2store(ptr, rpl->flags);
ptr+= 2;
int4store(ptr, rpl->server_id);
ptr+= 4;
memcpy(ptr, rpl->filename, rpl->filename_length);
ptr+= rpl->filename_length;
if (ma_simple_command(rpl->mysql, COM_BINLOG_DUMP, (const char *)buf, ptr - buf, 1, 0))
return 1;
return 0;
}
MARIADB_RPL_EVENT * STDCALL mariadb_rpl_fetch(MARIADB_RPL *rpl, MARIADB_RPL_EVENT *event)
{
unsigned char *ev;
size_t len;
MARIADB_RPL_EVENT *rpl_event= 0;
if (!rpl || !rpl->mysql)
return 0;
while (1) {
unsigned long pkt_len= ma_net_safe_read(rpl->mysql);
if (pkt_len == packet_error)
{
rpl->buffer_size= 0;
return 0;
}
/* EOF packet:
see https://mariadb.com/kb/en/library/eof_packet/
Packet length must be less than 9 bytes, EOF header
is 0xFE.
*/
if (pkt_len < 9 && rpl->mysql->net.read_pos[0] == 0xFE)
{
rpl->buffer_size= 0;
return 0;
}
/* if ignore heartbeat flag was set, we ignore this
record and continue to fetch next record.
The first byte is always status byte (0x00)
For event header description see
https://mariadb.com/kb/en/library/2-binlog-event-header/ */
if (rpl->flags & MARIADB_RPL_IGNORE_HEARTBEAT)
{
if (rpl->mysql->net.read_pos[1 + 4] == HEARTBEAT_LOG_EVENT)
continue;
}
rpl->buffer_size= pkt_len;
rpl->buffer= rpl->mysql->net.read_pos;
if (event)
{
MA_MEM_ROOT memroot= event->memroot;
rpl_event= event;
ma_free_root(&memroot, MYF(MY_KEEP_PREALLOC));
memset(rpl_event, 0, sizeof(MARIADB_RPL_EVENT));
rpl_event->memroot= memroot;
} else {
if (!(rpl_event = (MARIADB_RPL_EVENT *)malloc(sizeof(MARIADB_RPL_EVENT))))
goto mem_error;
memset(rpl_event, 0, sizeof(MARIADB_RPL_EVENT));
ma_init_alloc_root(&rpl_event->memroot, 8192, 0);
}
rpl_event->checksum= uint4korr(rpl->buffer + rpl->buffer_size - 4);
rpl_event->ok= rpl->buffer[0];
rpl_event->timestamp= uint4korr(rpl->buffer + 1);
rpl_event->event_type= (unsigned char)*(rpl->buffer + 5);
rpl_event->server_id= uint4korr(rpl->buffer + 6);
rpl_event->event_length= uint4korr(rpl->buffer + 10);
rpl_event->next_event_pos= uint4korr(rpl->buffer + 14);
rpl_event->flags= uint2korr(rpl->buffer + 18);
ev= rpl->buffer + EVENT_HEADER_OFS;
if (rpl->use_checksum)
{
rpl_event->checksum= *(ev + rpl_event->event_length - 4);
rpl_event->event_length-= 4;
}
switch(rpl_event->event_type) {
case HEARTBEAT_LOG_EVENT:
rpl_event->event.heartbeat.timestamp= uint4korr(ev);
ev+= 4;
rpl_event->event.heartbeat.next_position= uint4korr(ev);
ev+= 4;
rpl_event->event.heartbeat.type= (uint8_t)*ev;
ev+= 1;
rpl_event->event.heartbeat.flags= uint2korr(ev);
break;
case BINLOG_CHECKPOINT_EVENT:
len= uint4korr(ev);
ev+= 4;
if (rpl_alloc_string(rpl_event, &rpl_event->event.checkpoint.filename, ev, len))
goto mem_error;
break;
case FORMAT_DESCRIPTION_EVENT:
rpl_event->event.format_description.format = uint2korr(ev);
ev+= 2;
rpl_event->event.format_description.server_version = (char *)(ev);
ev+= 50;
rpl_event->event.format_description.timestamp= uint4korr(ev);
ev+= 4;
rpl->fd_header_len= rpl_event->event.format_description.header_len= (uint8_t)*ev;
ev= rpl->buffer + rpl->buffer_size - 5;
rpl->use_checksum= *ev;
break;
case QUERY_EVENT:
{
size_t db_len, status_len;
rpl_event->event.query.thread_id= uint4korr(ev);
ev+= 4;
rpl_event->event.query.seconds= uint4korr(ev);
ev+= 4;
db_len= *ev;
ev++;
rpl_event->event.query.errornr= uint2korr(ev);
ev+= 2;
status_len= uint2korr(ev);
ev+= 2;
if (rpl_alloc_string(rpl_event, &rpl_event->event.query.status, ev, status_len))
goto mem_error;
ev+= status_len;
if (rpl_alloc_string(rpl_event, &rpl_event->event.query.database, ev, db_len))
goto mem_error;
ev+= db_len + 1; /* zero terminated */
/* calculate statement size: buffer + buffer_size - current_ofs (ev) - crc_size */
len= (size_t)(rpl->buffer + rpl->buffer_size - ev - (rpl->use_checksum ? 4 : 0));
if (rpl_alloc_string(rpl_event, &rpl_event->event.query.statement, ev, len))
goto mem_error;
break;
}
case TABLE_MAP_EVENT:
rpl_event->event.table_map.table_id= uint6korr(ev);
ev+= 8;
len= *ev;
ev++;
if (rpl_alloc_string(rpl_event, &rpl_event->event.table_map.database, ev, len))
goto mem_error;
ev+= len + 1;
len= *ev;
ev++;
if (rpl_alloc_string(rpl_event, &rpl_event->event.table_map.table, ev, len))
goto mem_error;
ev+= len + 1;
rpl_event->event.table_map.column_count= mysql_net_field_length(&ev);
len= rpl_event->event.table_map.column_count;
if (rpl_alloc_string(rpl_event, &rpl_event->event.table_map.column_types, ev, len))
goto mem_error;
ev+= len;
len= mysql_net_field_length(&ev);
if (rpl_alloc_string(rpl_event, &rpl_event->event.table_map.metadata, ev, len))
goto mem_error;
break;
case RAND_EVENT:
rpl_event->event.rand.first_seed= uint8korr(ev);
ev+= 8;
rpl_event->event.rand.second_seed= uint8korr(ev);
break;
case INTVAR_EVENT:
rpl_event->event.intvar.type= *ev;
ev++;
rpl_event->event.intvar.value= uint8korr(ev);
break;
case USER_VAR_EVENT:
len= uint4korr(ev);
ev+= 4;
if (rpl_alloc_string(rpl_event, &rpl_event->event.uservar.name, ev, len))
goto mem_error;
ev+= len;
if (!(rpl_event->event.uservar.is_null= (uint8)*ev))
{
ev++;
rpl_event->event.uservar.type= *ev;
ev++;
rpl_event->event.uservar.charset_nr= uint4korr(ev);
ev+= 4;
len= uint4korr(ev);
ev+= 4;
if (rpl_alloc_string(rpl_event, &rpl_event->event.uservar.value, ev, len))
goto mem_error;
ev+= len;
if ((unsigned long)(ev - rpl->buffer) < rpl->buffer_size)
rpl_event->event.uservar.flags= *ev;
}
break;
case START_ENCRYPTION_EVENT:
rpl_event->event.encryption.scheme= *ev;
ev++;
rpl_event->event.encryption.key_version= uint4korr(ev);
ev+= 4;
rpl_event->event.encryption.nonce= (char *)ev;
break;
case ANNOTATE_ROWS_EVENT:
len= (uint32)(rpl->buffer + rpl->buffer_size - (unsigned char *)ev - (rpl->use_checksum ? 4 : 0));
if (rpl_alloc_string(rpl_event, &rpl_event->event.annotate_rows.statement, ev, len))
goto mem_error;
break;
case ROTATE_EVENT:
rpl_event->event.rotate.position= uint8korr(ev);
ev+= 8;
len= rpl_event->event_length - rpl->fd_header_len - 8;
if (rpl_alloc_string(rpl_event, &rpl_event->event.rotate.filename, ev, len))
goto mem_error;
break;
case XID_EVENT:
rpl_event->event.xid.transaction_nr= uint8korr(ev);
break;
case STOP_EVENT:
/* nothing to do here */
break;
case GTID_EVENT:
rpl_event->event.gtid.sequence_nr= uint8korr(ev);
ev+= 8;
rpl_event->event.gtid.domain_id= uint4korr(ev);
ev+= 4;
rpl_event->event.gtid.flags= *ev;
ev++;
if (rpl_event->event.gtid.flags & FL_GROUP_COMMIT_ID)
rpl_event->event.gtid.commit_id= uint8korr(ev);
break;
case GTID_LIST_EVENT:
{
uint32 i;
rpl_event->event.gtid_list.gtid_cnt= uint4korr(ev);
ev++;
if (!(rpl_event->event.gtid_list.gtid= (MARIADB_GTID *)ma_alloc_root(&rpl_event->memroot, sizeof(MARIADB_GTID) * rpl_event->event.gtid_list.gtid_cnt)))
goto mem_error;
for (i=0; i < rpl_event->event.gtid_list.gtid_cnt; i++)
{
rpl_event->event.gtid_list.gtid[i].domain_id= uint4korr(ev);
ev+= 4;
rpl_event->event.gtid_list.gtid[i].server_id= uint4korr(ev);
ev+= 4;
rpl_event->event.gtid_list.gtid[i].sequence_nr= uint8korr(ev);
ev+= 8;
}
break;
}
case WRITE_ROWS_EVENT_V1:
case UPDATE_ROWS_EVENT_V1:
case DELETE_ROWS_EVENT_V1:
rpl_event->event.rows.type= rpl_event->event_type - WRITE_ROWS_EVENT_V1;
if (rpl->fd_header_len == 6)
{
rpl_event->event.rows.table_id= uint4korr(ev);
ev+= 4;
} else {
rpl_event->event.rows.table_id= uint6korr(ev);
ev+= 6;
}
rpl_event->event.rows.flags= uint2korr(ev);
ev+= 2;
len= rpl_event->event.rows.column_count= mysql_net_field_length(&ev);
if (!len)
break;
if (!(rpl_event->event.rows.column_bitmap =
(char *)ma_alloc_root(&rpl_event->memroot, (len + 7) / 8)))
goto mem_error;
memcpy(rpl_event->event.rows.column_bitmap, ev, (len + 7) / 8);
ev+= (len + 7) / 8;
if (rpl_event->event_type == UPDATE_ROWS_EVENT_V1)
{
if (!(rpl_event->event.rows.column_update_bitmap =
(char *)ma_alloc_root(&rpl_event->memroot, (len + 7) / 8)))
goto mem_error;
memcpy(rpl_event->event.rows.column_update_bitmap, ev, (len + 7) / 8);
ev+= (len + 7) / 8;
}
len= (rpl->buffer + rpl_event->event_length + EVENT_HEADER_OFS - rpl->fd_header_len) - ev;
if ((rpl_event->event.rows.row_data_size= len))
{
if (!(rpl_event->event.rows.row_data =
(char *)ma_alloc_root(&rpl_event->memroot, rpl_event->event.rows.row_data_size)))
goto mem_error;
memcpy(rpl_event->event.rows.row_data, ev, rpl_event->event.rows.row_data_size);
}
break;
default:
free(rpl_event);
return NULL;
break;
}
return rpl_event;
}
mem_error:
free(rpl_event);
SET_CLIENT_ERROR(rpl->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return 0;
}
void STDCALL mariadb_rpl_close(MARIADB_RPL *rpl)
{
if (!rpl)
return;
if (rpl->filename)
free((void *)rpl->filename);
free(rpl);
return;
}
int mariadb_rpl_optionsv(MARIADB_RPL *rpl,
enum mariadb_rpl_option option,
...)
{
va_list ap;
int rc= 0;
if (!rpl)
return 1;
va_start(ap, option);
switch (option) {
case MARIADB_RPL_FILENAME:
{
char *arg1= va_arg(ap, char *);
rpl->filename_length= (uint32_t)va_arg(ap, size_t);
free((void *)rpl->filename);
rpl->filename= NULL;
if (rpl->filename_length)
{
rpl->filename= (char *)malloc(rpl->filename_length);
memcpy((void *)rpl->filename, arg1, rpl->filename_length);
}
else if (arg1)
{
rpl->filename= strdup((const char *)arg1);
rpl->filename_length= (uint32_t)strlen(rpl->filename);
}
break;
}
case MARIADB_RPL_SERVER_ID:
{
rpl->server_id= va_arg(ap, unsigned int);
break;
}
case MARIADB_RPL_FLAGS:
{
rpl->flags= va_arg(ap, unsigned int);
break;
}
case MARIADB_RPL_START:
{
rpl->start_position= va_arg(ap, unsigned long);
break;
}
default:
rc= -1;
goto end;
}
end:
va_end(ap);
return rc;
}
int mariadb_rpl_get_optionsv(MARIADB_RPL *rpl,
enum mariadb_rpl_option option,
...)
{
va_list ap;
if (!rpl)
return 1;
va_start(ap, option);
switch (option) {
case MARIADB_RPL_FILENAME:
{
const char **name= (const char **)va_arg(ap, char **);
size_t *len= (size_t*)va_arg(ap, size_t *);
*name= rpl->filename;
*len= rpl->filename_length;
break;
}
case MARIADB_RPL_SERVER_ID:
{
unsigned int *id= va_arg(ap, unsigned int *);
*id= rpl->server_id;
break;
}
case MARIADB_RPL_FLAGS:
{
unsigned int *flags= va_arg(ap, unsigned int *);
*flags= rpl->flags;
break;
}
case MARIADB_RPL_START:
{
unsigned long *start= va_arg(ap, unsigned long *);
*start= rpl->start_position;
break;
}
default:
va_end(ap);
return 1;
break;
}
va_end(ap);
return 0;
}

2515
vendor/MDBC/libmariadb/mariadb_stmt.c vendored Normal file

File diff suppressed because it is too large Load Diff

1463
vendor/MDBC/libmariadb/secure/gnutls.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
/*
Copyright (C) 2018 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*/
#include <ma_crypt.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
static gnutls_digest_algorithm_t ma_hash_get_algorithm(unsigned int alg)
{
switch(alg)
{
case MA_HASH_MD5:
return GNUTLS_DIG_MD5;
case MA_HASH_SHA1:
return GNUTLS_DIG_SHA1;
case MA_HASH_SHA256:
return GNUTLS_DIG_SHA256;
case MA_HASH_SHA384:
return GNUTLS_DIG_SHA384;
case MA_HASH_SHA512:
return GNUTLS_DIG_SHA512;
case MA_HASH_RIPEMD160:
return GNUTLS_DIG_RMD160;
default:
return GNUTLS_DIG_UNKNOWN;
}
}
MA_HASH_CTX *ma_hash_new(unsigned int algorithm, MA_HASH_CTX *unused_ctx __attribute__((unused)))
{
gnutls_hash_hd_t ctx= NULL;
gnutls_digest_algorithm_t hash_alg= ma_hash_get_algorithm(algorithm);
/* unknown or unsupported hash algorithm */
if (hash_alg == GNUTLS_DIG_UNKNOWN)
return NULL;
if (gnutls_hash_init(&ctx, hash_alg) < 0)
return NULL;
return (MA_HASH_CTX *)ctx;
}
void ma_hash_free(MA_HASH_CTX *ctx)
{
if (ctx)
gnutls_hash_deinit((gnutls_hash_hd_t)ctx, NULL);
}
void ma_hash_input(MA_HASH_CTX *ctx,
const unsigned char *buffer,
size_t len)
{
gnutls_hash((gnutls_hash_hd_t)ctx, (const void *)buffer, len);
}
void ma_hash_result(MA_HASH_CTX *ctx, unsigned char *digest)
{
gnutls_hash_output((gnutls_hash_hd_t)ctx, digest);
}

View File

@ -0,0 +1,637 @@
/************************************************************************************
Copyright (C) 2014 MariaDB Corporation Ab
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
Author: Georg Richter
*************************************************************************************/
#include "ma_schannel.h"
#include "schannel_certs.h"
#include <assert.h>
#define SC_IO_BUFFER_SIZE 0x4000
#define MAX_SSL_ERR_LEN 100
#define SCHANNEL_PAYLOAD(A) ((A).cbMaximumMessage + (A).cbHeader + (A).cbTrailer)
void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
/* {{{ void ma_schannel_set_sec_error */
void ma_schannel_set_sec_error(MARIADB_PVIO* pvio, DWORD ErrorNo)
{
MYSQL* mysql = pvio->mysql;
if (ErrorNo != SEC_E_OK)
mysql->net.extension->extended_errno = ErrorNo;
if (ErrorNo == SEC_E_INTERNAL_ERROR && GetLastError())
{
ma_schannel_set_win_error(pvio, GetLastError());
return;
}
ma_schannel_set_win_error(pvio, ErrorNo);
}
/* }}} */
#include "win32_errmsg.h"
/* {{{ void ma_schnnel_set_win_error */
void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo)
{
char buffer[256];
ma_format_win32_error(buffer, sizeof(buffer), ErrorNo, "SSL connection error: ");
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, buffer);
return;
}
/* }}} */
/* }}} */
/* {{{ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData) */
/*
perform handshake loop
SYNOPSIS
ma_schannel_handshake_loop()
pvio Pointer to an Communication/IO structure
InitialRead TRUE if it's the very first read
ExtraData Pointer to an SecBuffer which contains extra data (sent by application)
*/
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData)
{
SecBufferDesc OutBuffer, InBuffer;
SecBuffer InBuffers[2], OutBuffers;
DWORD dwSSPIFlags, dwSSPIOutFlags, cbData, cbIoBuffer;
TimeStamp tsExpiry;
SECURITY_STATUS rc;
PUCHAR IoBuffer;
BOOL fDoRead;
MARIADB_TLS *ctls= pvio->ctls;
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
/* Allocate data buffer */
if (!(IoBuffer = LocalAlloc(LMEM_FIXED, SC_IO_BUFFER_SIZE)))
return SEC_E_INSUFFICIENT_MEMORY;
cbIoBuffer = 0;
fDoRead = InitialRead;
/* handshake loop: We will leave if handshake is finished
or an error occurs */
rc = SEC_I_CONTINUE_NEEDED;
while (rc == SEC_I_CONTINUE_NEEDED ||
rc == SEC_E_INCOMPLETE_MESSAGE ||
rc == SEC_I_INCOMPLETE_CREDENTIALS )
{
/* Read data */
if (rc == SEC_E_INCOMPLETE_MESSAGE ||
!cbIoBuffer)
{
if(fDoRead)
{
ssize_t nbytes = pvio->methods->read(pvio, IoBuffer + cbIoBuffer, (size_t)(SC_IO_BUFFER_SIZE - cbIoBuffer));
if (nbytes <= 0)
{
rc = SEC_E_INTERNAL_ERROR;
break;
}
cbData = (DWORD)nbytes;
cbIoBuffer += cbData;
}
else
fDoRead = TRUE;
}
/* input buffers
First buffer stores data received from server. leftover data
will be stored in second buffer with BufferType SECBUFFER_EXTRA */
InBuffers[0].pvBuffer = IoBuffer;
InBuffers[0].cbBuffer = cbIoBuffer;
InBuffers[0].BufferType = SECBUFFER_TOKEN;
InBuffers[1].pvBuffer = NULL;
InBuffers[1].cbBuffer = 0;
InBuffers[1].BufferType = SECBUFFER_EMPTY;
InBuffer.cBuffers = 2;
InBuffer.pBuffers = InBuffers;
InBuffer.ulVersion = SECBUFFER_VERSION;
/* output buffer */
OutBuffers.pvBuffer = NULL;
OutBuffers.BufferType= SECBUFFER_TOKEN;
OutBuffers.cbBuffer = 0;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = &OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
rc = InitializeSecurityContextA(&sctx->CredHdl,
&sctx->hCtxt,
NULL,
dwSSPIFlags,
0,
SECURITY_NATIVE_DREP,
&InBuffer,
0,
NULL,
&OutBuffer,
&dwSSPIOutFlags,
&tsExpiry );
if (rc == SEC_E_OK ||
rc == SEC_I_CONTINUE_NEEDED ||
(FAILED(rc) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)))
{
if(OutBuffers.cbBuffer && OutBuffers.pvBuffer)
{
ssize_t nbytes = pvio->methods->write(pvio, (uchar *)OutBuffers.pvBuffer, (size_t)OutBuffers.cbBuffer);
if(nbytes <= 0)
{
FreeContextBuffer(OutBuffers.pvBuffer);
DeleteSecurityContext(&sctx->hCtxt);
return SEC_E_INTERNAL_ERROR;
}
cbData= (DWORD)nbytes;
/* Free output context buffer */
FreeContextBuffer(OutBuffers.pvBuffer);
OutBuffers.pvBuffer = NULL;
}
}
/* check if we need to read more data */
switch (rc) {
case SEC_E_INCOMPLETE_MESSAGE:
/* we didn't receive all data, so just continue loop */
continue;
break;
case SEC_E_OK:
/* handshake completed, but we need to check if extra
data was sent (which contains encrypted application data) */
if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
{
if (!(pExtraData->pvBuffer= LocalAlloc(0, InBuffers[1].cbBuffer)))
return SEC_E_INSUFFICIENT_MEMORY;
MoveMemory(pExtraData->pvBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer );
pExtraData->BufferType = SECBUFFER_TOKEN;
pExtraData->cbBuffer = InBuffers[1].cbBuffer;
}
else
{
pExtraData->BufferType= SECBUFFER_EMPTY;
pExtraData->pvBuffer= NULL;
pExtraData->cbBuffer= 0;
}
break;
case SEC_I_INCOMPLETE_CREDENTIALS:
/* Provided credentials didn't contain a valid client certificate.
We will try to connect anonymously, using current credentials */
fDoRead= FALSE;
rc= SEC_I_CONTINUE_NEEDED;
continue;
break;
default:
if (FAILED(rc))
{
goto loopend;
}
break;
}
if ( InBuffers[1].BufferType == SECBUFFER_EXTRA )
{
MoveMemory( IoBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer );
cbIoBuffer = InBuffers[1].cbBuffer;
}
else
cbIoBuffer = 0;
}
loopend:
if (FAILED(rc))
{
ma_schannel_set_sec_error(pvio, rc);
DeleteSecurityContext(&sctx->hCtxt);
}
LocalFree(IoBuffer);
return rc;
}
/* }}} */
/* {{{ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls) */
/*
performs client side handshake
SYNOPSIS
ma_schannel_client_handshake()
ctls Pointer to a MARIADB_TLS structure
DESCRIPTION
initiates a client/server handshake. This function can be used
by clients only
RETURN
SEC_E_OK on success
*/
SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls)
{
MARIADB_PVIO *pvio;
SECURITY_STATUS sRet;
DWORD OutFlags;
DWORD r;
SC_CTX *sctx;
SecBuffer ExtraData;
DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
ISC_REQ_USE_SUPPLIED_CREDS |
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
SecBufferDesc BufferOut;
SecBuffer BuffersOut;
if (!ctls || !ctls->pvio)
return 1;
pvio= ctls->pvio;
sctx= (SC_CTX *)ctls->ssl;
/* Initialie securifty context */
BuffersOut.BufferType= SECBUFFER_TOKEN;
BuffersOut.cbBuffer= 0;
BuffersOut.pvBuffer= NULL;
BufferOut.cBuffers= 1;
BufferOut.pBuffers= &BuffersOut;
BufferOut.ulVersion= SECBUFFER_VERSION;
sRet = InitializeSecurityContext(&sctx->CredHdl,
NULL,
pvio->mysql->host,
SFlags,
0,
SECURITY_NATIVE_DREP,
NULL,
0,
&sctx->hCtxt,
&BufferOut,
&OutFlags,
NULL);
if(sRet != SEC_I_CONTINUE_NEEDED)
{
ma_schannel_set_sec_error(pvio, sRet);
return sRet;
}
/* send client hello packaet */
if(BuffersOut.cbBuffer != 0 && BuffersOut.pvBuffer != NULL)
{
ssize_t nbytes = (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut.pvBuffer, (size_t)BuffersOut.cbBuffer);
if (nbytes <= 0)
{
sRet= SEC_E_INTERNAL_ERROR;
goto end;
}
r = (DWORD)nbytes;
}
sRet= ma_schannel_handshake_loop(pvio, TRUE, &ExtraData);
/* allocate IO-Buffer for write operations: After handshake
was successful, we are able now to calculate payload */
if ((sRet = QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_STREAM_SIZES, &sctx->Sizes )))
goto end;
sctx->IoBufferSize= SCHANNEL_PAYLOAD(sctx->Sizes);
if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(0, sctx->IoBufferSize)))
{
sRet= SEC_E_INSUFFICIENT_MEMORY;
goto end;
}
return sRet;
end:
if (BuffersOut.pvBuffer)
FreeContextBuffer(BuffersOut.pvBuffer);
return sRet;
}
/* }}} */
/* {{{ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio, PCredHandle phCreds, CtxtHandle * phContext,
DWORD DecryptLength, uchar *ReadBuffer, DWORD ReadBufferSize) */
/*
Reads encrypted data from a SSL stream and decrypts it.
SYNOPSIS
ma_schannel_read
pvio pointer to Communication IO structure
phContext a context handle
DecryptLength size of decrypted buffer
ReadBuffer Buffer for decrypted data
ReadBufferSize size of ReadBuffer
DESCRIPTION
Reads decrypted data from a SSL stream and encrypts it.
RETURN
SEC_E_OK on success
SEC_E_* if an error occurred
*/
SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio,
CtxtHandle * phContext,
DWORD *DecryptLength,
uchar *ReadBuffer,
DWORD ReadBufferSize)
{
ssize_t nbytes = 0;
DWORD dwOffset = 0;
SC_CTX *sctx;
SECURITY_STATUS sRet = 0;
SecBufferDesc Msg;
SecBuffer Buffers[4];
int i;
if (!pvio || !pvio->methods || !pvio->methods->read || !pvio->ctls || !DecryptLength)
return SEC_E_INTERNAL_ERROR;
sctx = (SC_CTX *)pvio->ctls->ssl;
*DecryptLength = 0;
if (sctx->dataBuf.cbBuffer)
{
/* Have unread decrypted data from the last time, copy. */
nbytes = MIN(ReadBufferSize, sctx->dataBuf.cbBuffer);
memcpy(ReadBuffer, sctx->dataBuf.pvBuffer, nbytes);
sctx->dataBuf.pvBuffer = (char *)(sctx->dataBuf.pvBuffer) + nbytes;
sctx->dataBuf.cbBuffer -= (DWORD)nbytes;
*DecryptLength = (DWORD)nbytes;
return SEC_E_OK;
}
while (1)
{
/* Check for any encrypted data returned by last DecryptMessage() in SECBUFFER_EXTRA buffer. */
if (sctx->extraBuf.cbBuffer)
{
memmove(sctx->IoBuffer, sctx->extraBuf.pvBuffer, sctx->extraBuf.cbBuffer);
dwOffset = sctx->extraBuf.cbBuffer;
sctx->extraBuf.cbBuffer = 0;
}
do {
assert(sctx->IoBufferSize > dwOffset);
if (dwOffset == 0 || sRet == SEC_E_INCOMPLETE_MESSAGE)
{
nbytes = pvio->methods->read(pvio, sctx->IoBuffer + dwOffset, (size_t)(sctx->IoBufferSize - dwOffset));
if (nbytes <= 0)
{
/* server closed connection, or an error */
// todo: error
return SEC_E_INVALID_HANDLE;
}
dwOffset += (DWORD)nbytes;
}
ZeroMemory(Buffers, sizeof(SecBuffer) * 4);
Buffers[0].pvBuffer = sctx->IoBuffer;
Buffers[0].cbBuffer = dwOffset;
Buffers[0].BufferType = SECBUFFER_DATA;
Buffers[1].BufferType = SECBUFFER_EMPTY;
Buffers[2].BufferType = SECBUFFER_EMPTY;
Buffers[3].BufferType = SECBUFFER_EMPTY;
Msg.ulVersion = SECBUFFER_VERSION; // Version number
Msg.cBuffers = 4;
Msg.pBuffers = Buffers;
sRet = DecryptMessage(phContext, &Msg, 0, NULL);
} while (sRet == SEC_E_INCOMPLETE_MESSAGE); /* Continue reading until full message arrives */
if (sRet != SEC_E_OK)
{
ma_schannel_set_sec_error(pvio, sRet);
return sRet;
}
sctx->extraBuf.cbBuffer = 0;
sctx->dataBuf.cbBuffer = 0;
for (i = 0; i < 4; i++)
{
if (Buffers[i].BufferType == SECBUFFER_DATA)
sctx->dataBuf = Buffers[i];
if (Buffers[i].BufferType == SECBUFFER_EXTRA)
sctx->extraBuf = Buffers[i];
}
if (sctx->dataBuf.cbBuffer)
{
assert(sctx->dataBuf.pvBuffer);
/*
Copy at most ReadBufferSize bytes to output.
Store the rest (if any) to be processed next time.
*/
nbytes = MIN(sctx->dataBuf.cbBuffer, ReadBufferSize);
memcpy((char *)ReadBuffer, sctx->dataBuf.pvBuffer, nbytes);
sctx->dataBuf.cbBuffer -= (unsigned long)nbytes;
sctx->dataBuf.pvBuffer = (char *)sctx->dataBuf.pvBuffer + nbytes;
*DecryptLength = (DWORD)nbytes;
return SEC_E_OK;
}
// No data buffer, loop
}
}
/* }}} */
#include "win32_errmsg.h"
my_bool ma_schannel_verify_certs(MARIADB_TLS *ctls, BOOL verify_server_name)
{
SECURITY_STATUS status;
MARIADB_PVIO *pvio= ctls->pvio;
MYSQL *mysql= pvio->mysql;
SC_CTX *sctx = (SC_CTX *)ctls->ssl;
const char *ca_file= mysql->options.ssl_ca;
const char* ca_path = mysql->options.ssl_capath;
const char *crl_file= mysql->options.extension ? mysql->options.extension->ssl_crl : NULL;
const char* crl_path = mysql->options.extension ? mysql->options.extension->ssl_crlpath : NULL;
PCCERT_CONTEXT pServerCert= NULL;
char errmsg[256];
HCERTSTORE store= NULL;
int ret= 0;
status = schannel_create_store(ca_file, ca_path, crl_file, crl_path, &store, errmsg, sizeof(errmsg));
if(status)
goto end;
status = QueryContextAttributesA(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert);
if (status)
{
ma_format_win32_error(errmsg, sizeof(errmsg), GetLastError(),
"QueryContextAttributes(SECPKG_ATTR_REMOTE_CERT_CONTEXT) failed.");
goto end;
}
status = schannel_verify_server_certificate(
pServerCert,
store,
crl_file != 0 || crl_path != 0,
mysql->host,
verify_server_name,
errmsg, sizeof(errmsg));
if (status)
goto end;
ret= 1;
end:
if (!ret)
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
"SSL connection error: %s", errmsg);
}
if (pServerCert)
CertFreeCertificateContext(pServerCert);
if(store)
schannel_free_store(store);
return ret;
}
/* {{{ size_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio, PCredHandle phCreds, CtxtHandle * phContext) */
/*
Decrypts data and write to SSL stream
SYNOPSIS
ma_schannel_write_decrypt
pvio pointer to Communication IO structure
phContext a context handle
DecryptLength size of decrypted buffer
ReadBuffer Buffer for decrypted data
ReadBufferSize size of ReadBuffer
DESCRIPTION
Write encrypted data to SSL stream.
RETURN
SEC_E_OK on success
SEC_E_* if an error occurred
*/
ssize_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio,
uchar *WriteBuffer,
size_t WriteBufferSize)
{
SECURITY_STATUS scRet;
SecBufferDesc Message;
SecBuffer Buffers[4];
DWORD cbMessage;
PBYTE pbMessage;
SC_CTX *sctx= (SC_CTX *)pvio->ctls->ssl;
size_t payload;
ssize_t nbytes;
DWORD write_size;
payload= MIN(WriteBufferSize, sctx->Sizes.cbMaximumMessage);
memcpy(&sctx->IoBuffer[sctx->Sizes.cbHeader], WriteBuffer, payload);
pbMessage = sctx->IoBuffer + sctx->Sizes.cbHeader;
cbMessage = (DWORD)payload;
Buffers[0].pvBuffer = sctx->IoBuffer;
Buffers[0].cbBuffer = sctx->Sizes.cbHeader;
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER; // Type of the buffer
Buffers[1].pvBuffer = &sctx->IoBuffer[sctx->Sizes.cbHeader];
Buffers[1].cbBuffer = (DWORD)payload;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[2].pvBuffer = &sctx->IoBuffer[sctx->Sizes.cbHeader] + payload;
Buffers[2].cbBuffer = sctx->Sizes.cbTrailer;
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
Buffers[3].pvBuffer = SECBUFFER_EMPTY; // Pointer to buffer 4
Buffers[3].cbBuffer = SECBUFFER_EMPTY; // length of buffer 4
Buffers[3].BufferType = SECBUFFER_EMPTY; // Type of the buffer 4
Message.ulVersion = SECBUFFER_VERSION;
Message.cBuffers = 4;
Message.pBuffers = Buffers;
if ((scRet = EncryptMessage(&sctx->hCtxt, 0, &Message, 0))!= SEC_E_OK)
return -1;
write_size = Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer;
nbytes = pvio->methods->write(pvio, sctx->IoBuffer, write_size);
return nbytes == write_size ? payload : -1;
}
/* }}} */
extern char *ssl_protocol_version[5];
/* {{{ ma_tls_get_protocol_version(MARIADB_TLS *ctls) */
int ma_tls_get_protocol_version(MARIADB_TLS *ctls)
{
SC_CTX *sctx;
SecPkgContext_ConnectionInfo ConnectionInfo;
if (!ctls->ssl)
return 1;
sctx= (SC_CTX *)ctls->ssl;
if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_CONNECTION_INFO, &ConnectionInfo) != SEC_E_OK)
return -1;
switch(ConnectionInfo.dwProtocol)
{
case SP_PROT_SSL3_CLIENT:
return PROTOCOL_SSLV3;
case SP_PROT_TLS1_CLIENT:
return PROTOCOL_TLS_1_0;
case SP_PROT_TLS1_1_CLIENT:
return PROTOCOL_TLS_1_1;
case SP_PROT_TLS1_2_CLIENT:
return PROTOCOL_TLS_1_2;
default:
return -1;
}
}
/* }}} */

View File

@ -0,0 +1,87 @@
/************************************************************************************
Copyright (C) 2014 MariaDB Corporation Ab
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
Author: Georg Richter
*************************************************************************************/
#ifndef _ma_schannel_h_
#define _ma_schannel_h_
#define SECURITY_WIN32
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_common.h>
#include <ma_pvio.h>
#include <errmsg.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <security.h>
#include <schnlsp.h>
#undef SECURITY_WIN32
#include <windows.h>
#include <sspi.h>
#define SC_IO_BUFFER_SIZE 0x4000
#include <ma_pthread.h>
struct st_DER {
char* der_buffer;
DWORD der_length;
};
struct st_schannel {
CredHandle CredHdl;
PUCHAR IoBuffer;
DWORD IoBufferSize;
SecPkgContext_StreamSizes Sizes;
CtxtHandle hCtxt;
/* Cached data from the last read/decrypt call.*/
SecBuffer extraBuf; /* encrypted data read from server. */
SecBuffer dataBuf; /* decrypted but still unread data from server.*/
};
typedef struct st_schannel SC_CTX;
extern HCERTSTORE ca_CertStore, crl_CertStore;
extern my_bool ca_Check, crl_Check;
;
SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls);
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData);
my_bool ma_schannel_verify_certs(MARIADB_TLS *ctls, BOOL verify_server_name);
ssize_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio,
uchar *WriteBuffer,
size_t WriteBufferSize);
SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio,
CtxtHandle* phContext,
DWORD *DecryptLength,
uchar *ReadBuffer,
DWORD ReadBufferSize);
#endif /* _ma_schannel_h_ */

797
vendor/MDBC/libmariadb/secure/openssl.c vendored Normal file
View File

@ -0,0 +1,797 @@
/************************************************************************************
Copyright (C) 2012 Monty Program AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include <ma_global.h>
#include <ma_sys.h>
#include <ma_common.h>
#include <ma_pvio.h>
#include <errmsg.h>
#include <string.h>
#include <mysql/client_plugin.h>
#include <string.h>
#include <openssl/ssl.h> /* SSL and SSL_CTX */
#include <openssl/err.h> /* error reporting */
#include <openssl/conf.h>
#include <openssl/md4.h>
#if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C)
#include <openssl/applink.c>
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
#include <openssl/x509v3.h>
#define HAVE_OPENSSL_CHECK_HOST 1
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
#define HAVE_OPENSSL_1_1_API
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L
#define SSL_OP_NO_TLSv1_1 0L
#define SSL_OP_NO_TLSv1_2 0L
#define CRYPTO_THREADID_set_callback CRYPTO_set_id_callback
#define CRYPTO_THREADID_get_callback CRYPTO_get_id_callback
#endif
#if defined(OPENSSL_USE_BIOMETHOD)
#undef OPENSSL_USE_BIOMETHOD
#endif
#ifndef HAVE_OPENSSL_DEFAULT
#include <memory.h>
#define ma_malloc(A,B) malloc((A))
#undef ma_free
#define ma_free(A) free((A))
#define ma_snprintf snprintf
#define ma_vsnprintf vsnprintf
#undef SAFE_MUTEX
#endif
#include <ma_pthread.h>
#include <mariadb_async.h>
#include <ma_context.h>
extern my_bool ma_tls_initialized;
extern unsigned int mariadb_deinitialize_ssl;
#define MAX_SSL_ERR_LEN 100
char tls_library_version[TLS_VERSION_LENGTH];
static pthread_mutex_t LOCK_openssl_config;
#ifndef HAVE_OPENSSL_1_1_API
static pthread_mutex_t *LOCK_crypto= NULL;
#endif
#if defined(OPENSSL_USE_BIOMETHOD)
static int ma_bio_read(BIO *h, char *buf, int size);
static int ma_bio_write(BIO *h, const char *buf, int size);
static BIO_METHOD ma_BIO_method;
#endif
static long ma_tls_version_options(const char *version)
{
long protocol_options,
disable_all_protocols;
protocol_options= disable_all_protocols=
SSL_OP_NO_SSLv2 |
SSL_OP_NO_SSLv3 |
SSL_OP_NO_TLSv1 |
SSL_OP_NO_TLSv1_1 |
SSL_OP_NO_TLSv1_2
#ifdef TLS1_3_VERSION
| SSL_OP_NO_TLSv1_3
#endif
;
if (!version)
return 0;
if (strstr(version, "TLSv1.0"))
protocol_options&= ~SSL_OP_NO_TLSv1;
if (strstr(version, "TLSv1.1"))
protocol_options&= ~SSL_OP_NO_TLSv1_1;
if (strstr(version, "TLSv1.2"))
protocol_options&= ~SSL_OP_NO_TLSv1_2;
#ifdef TLS1_3_VERSION
if (strstr(version, "TLSv1.3"))
protocol_options&= ~SSL_OP_NO_TLSv1_3;
#endif
if (protocol_options != disable_all_protocols)
return protocol_options;
return 0;
}
static void ma_tls_set_error(MYSQL *mysql)
{
ulong ssl_errno= ERR_get_error();
char ssl_error[MAX_SSL_ERR_LEN];
const char *ssl_error_reason;
MARIADB_PVIO *pvio= mysql->net.pvio;
if (!ssl_errno)
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
return;
}
if ((ssl_error_reason= ERR_reason_error_string(ssl_errno)))
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
0, ssl_error_reason);
return;
}
snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%lu", ssl_errno);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0, ssl_error);
return;
}
#ifndef HAVE_OPENSSL_1_1_API
/*
thread safe callbacks for OpenSSL
Crypto call back functions will be
set during ssl_initialization
*/
#if OPENSSL_VERSION_NUMBER < 0x10000000L
static unsigned long my_cb_threadid(void)
{
/* cast pthread_t to unsigned long */
return (unsigned long) pthread_self();
}
#else
static void my_cb_threadid(CRYPTO_THREADID *id)
{
CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
}
#endif
#endif
#ifndef HAVE_OPENSSL_1_1_API
static void my_cb_locking(int mode, int n,
const char *file __attribute__((unused)),
int line __attribute__((unused)))
{
if (mode & CRYPTO_LOCK)
pthread_mutex_lock(&LOCK_crypto[n]);
else
pthread_mutex_unlock(&LOCK_crypto[n]);
}
static int ssl_thread_init()
{
if (!CRYPTO_THREADID_get_callback()
#ifndef OPENSSL_NO_DEPRECATED
&& !CRYPTO_get_id_callback()
#endif
)
{
int i, max= CRYPTO_num_locks();
if (LOCK_crypto == NULL)
{
if (!(LOCK_crypto=
(pthread_mutex_t *)ma_malloc(sizeof(pthread_mutex_t) * max, MYF(0))))
return 1;
for (i=0; i < max; i++)
pthread_mutex_init(&LOCK_crypto[i], NULL);
}
CRYPTO_set_locking_callback(my_cb_locking);
CRYPTO_THREADID_set_callback(my_cb_threadid);
}
return 0;
}
#endif
#if defined(_WIN32) || !defined(DISABLE_SIGPIPE)
#define disable_sigpipe()
#else
#include <signal.h>
static void ma_sigpipe_handler()
{
}
static void disable_sigpipe()
{
struct sigaction old_handler, new_handler={NULL};
if (!sigaction (SIGPIPE, NULL, &old_handler) &&
!old_handler.sa_handler)
{
new_handler.sa_handler= ma_sigpipe_handler;
new_handler.sa_flags= 0;
if (!sigemptyset(&new_handler.sa_mask))
sigaction(SIGPIPE, &new_handler, NULL);
}
}
#endif
/*
Initializes SSL
SYNOPSIS
my_ssl_start
mysql connection handle
RETURN VALUES
0 success
1 error
*/
int ma_tls_start(char *errmsg __attribute__((unused)), size_t errmsg_len __attribute__((unused)))
{
int rc= 1;
char *p;
if (ma_tls_initialized)
return 0;
/* lock mutex to prevent multiple initialization */
pthread_mutex_init(&LOCK_openssl_config, NULL);
pthread_mutex_lock(&LOCK_openssl_config);
#ifdef HAVE_OPENSSL_1_1_API
if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL))
goto end;
#else
if (ssl_thread_init())
{
strncpy(errmsg, "Not enough memory", errmsg_len);
goto end;
}
SSL_library_init();
#if SSLEAY_VERSION_NUMBER >= 0x00907000L
OPENSSL_config(NULL);
#endif
#endif
#ifndef HAVE_OPENSSL_1_1_API
/* load errors */
SSL_load_error_strings();
/* digests and ciphers */
OpenSSL_add_all_algorithms();
#endif
disable_sigpipe();
#ifdef OPENSSL_USE_BIOMETHOD
memcpy(&ma_BIO_method, BIO_s_socket(), sizeof(BIO_METHOD));
ma_BIO_method.bread= ma_bio_read;
ma_BIO_method.bwrite= ma_bio_write;
#endif
snprintf(tls_library_version, TLS_VERSION_LENGTH - 1, "%s",
#if defined(LIBRESSL_VERSION_NUMBER) || !defined(HAVE_OPENSSL_1_1_API)
SSLeay_version(SSLEAY_VERSION));
#else
OpenSSL_version(OPENSSL_VERSION));
#endif
/* remove date from version */
if ((p= strstr(tls_library_version, " ")))
*p= 0;
rc= 0;
ma_tls_initialized= TRUE;
end:
pthread_mutex_unlock(&LOCK_openssl_config);
return rc;
}
/*
Release SSL and free resources
Will be automatically executed by
mysql_server_end() function
SYNOPSIS
my_ssl_end()
void
RETURN VALUES
void
*/
void ma_tls_end()
{
if (ma_tls_initialized)
{
pthread_mutex_lock(&LOCK_openssl_config);
#ifndef HAVE_OPENSSL_1_1_API
if (LOCK_crypto)
{
int i;
CRYPTO_set_locking_callback(NULL);
CRYPTO_THREADID_set_callback(NULL);
for (i=0; i < CRYPTO_num_locks(); i++)
pthread_mutex_destroy(&LOCK_crypto[i]);
ma_free((gptr)LOCK_crypto);
LOCK_crypto= NULL;
}
#endif
if (mariadb_deinitialize_ssl)
{
#ifndef HAVE_OPENSSL_1_1_API
ERR_remove_thread_state(NULL);
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
CONF_modules_free();
CONF_modules_unload(1);
#endif
}
ma_tls_initialized= FALSE;
pthread_mutex_unlock(&LOCK_openssl_config);
pthread_mutex_destroy(&LOCK_openssl_config);
}
return;
}
int ma_tls_get_password(char *buf, int size,
int rwflag __attribute__((unused)),
void *userdata)
{
memset(buf, 0, size);
if (userdata)
strncpy(buf, (char *)userdata, size);
return (int)strlen(buf);
}
static int ma_tls_set_certs(MYSQL *mysql, SSL_CTX *ctx)
{
char *certfile= mysql->options.ssl_cert,
*keyfile= mysql->options.ssl_key;
char *pw= (mysql->options.extension) ?
mysql->options.extension->tls_pw : NULL;
/* add cipher */
if ((mysql->options.ssl_cipher &&
mysql->options.ssl_cipher[0] != 0))
{
if(
#ifdef TLS1_3_VERSION
SSL_CTX_set_ciphersuites(ctx, mysql->options.ssl_cipher) == 0 &&
#endif
SSL_CTX_set_cipher_list(ctx, mysql->options.ssl_cipher) == 0)
goto error;
}
/* ca_file and ca_path */
if (!SSL_CTX_load_verify_locations(ctx,
mysql->options.ssl_ca,
mysql->options.ssl_capath))
{
if (mysql->options.ssl_ca || mysql->options.ssl_capath)
goto error;
if (SSL_CTX_set_default_verify_paths(ctx) == 0)
goto error;
}
if (mysql->options.extension &&
(mysql->options.extension->ssl_crl || mysql->options.extension->ssl_crlpath))
{
X509_STORE *certstore;
if ((certstore= SSL_CTX_get_cert_store(ctx)))
{
if (X509_STORE_load_locations(certstore, mysql->options.extension->ssl_crl,
mysql->options.extension->ssl_crlpath) == 0)
goto error;
if (X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL) == 0)
goto error;
}
}
if (keyfile && !certfile)
certfile= keyfile;
if (certfile && !keyfile)
keyfile= certfile;
/* set cert */
if (certfile && certfile[0] != 0)
{
if (SSL_CTX_use_certificate_chain_file(ctx, certfile) != 1)
{
goto error;
}
}
if (keyfile && keyfile[0])
{
FILE *fp;
if ((fp= fopen(keyfile, "rb")))
{
EVP_PKEY *key= EVP_PKEY_new();
PEM_read_PrivateKey(fp, &key, NULL, pw);
fclose(fp);
if (SSL_CTX_use_PrivateKey(ctx, key) != 1)
{
unsigned long err= ERR_peek_error();
EVP_PKEY_free(key);
if (!(ERR_GET_LIB(err) == ERR_LIB_X509 &&
ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE))
goto error;
}
EVP_PKEY_free(key);
} else {
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
CER(CR_FILE_NOT_FOUND), keyfile);
return 1;
}
}
/* verify key */
if (certfile && SSL_CTX_check_private_key(ctx) != 1)
goto error;
SSL_CTX_set_verify(ctx, (mysql->options.ssl_ca || mysql->options.ssl_capath) ?
SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
return 0;
error:
ma_tls_set_error(mysql);
return 1;
}
void *ma_tls_init(MYSQL *mysql)
{
SSL *ssl= NULL;
SSL_CTX *ctx= NULL;
long default_options= SSL_OP_ALL |
SSL_OP_NO_SSLv2 |
SSL_OP_NO_SSLv3;
long options= 0;
pthread_mutex_lock(&LOCK_openssl_config);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
if (!(ctx= SSL_CTX_new(TLS_client_method())))
#else
if (!(ctx= SSL_CTX_new(SSLv23_client_method())))
#endif
goto error;
if (mysql->options.extension)
options= ma_tls_version_options(mysql->options.extension->tls_version);
SSL_CTX_set_options(ctx, options ? options : default_options);
if (ma_tls_set_certs(mysql, ctx))
{
goto error;
}
if (!(ssl= SSL_new(ctx)))
goto error;
if (!SSL_set_app_data(ssl, mysql))
goto error;
pthread_mutex_unlock(&LOCK_openssl_config);
return (void *)ssl;
error:
pthread_mutex_unlock(&LOCK_openssl_config);
if (ctx)
SSL_CTX_free(ctx);
if (ssl)
SSL_free(ssl);
return NULL;
}
my_bool ma_tls_connect(MARIADB_TLS *ctls)
{
SSL *ssl = (SSL *)ctls->ssl;
my_bool blocking, try_connect= 1;
MYSQL *mysql;
MARIADB_PVIO *pvio;
int rc;
#ifdef OPENSSL_USE_BIOMETHOD
BIO_METHOD *bio_method= NULL;
BIO *bio;
#endif
mysql= (MYSQL *)SSL_get_app_data(ssl);
pvio= mysql->net.pvio;
/* Set socket to non blocking if not already set */
if (!(blocking= pvio->methods->is_blocking(pvio)))
pvio->methods->blocking(pvio, FALSE, 0);
SSL_clear(ssl);
#ifdef OPENSSL_USE_BIOMETHOD
bio= BIO_new(&ma_BIO_method);
bio->ptr= pvio;
SSL_set_bio(ssl, bio, bio);
BIO_set_fd(bio, mysql_get_socket(mysql), BIO_NOCLOSE);
#else
SSL_set_fd(ssl, (int)mysql_get_socket(mysql));
#endif
while (try_connect && (rc= SSL_connect(ssl)) == -1)
{
switch((SSL_get_error(ssl, rc))) {
case SSL_ERROR_WANT_READ:
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, mysql->options.connect_timeout) < 1)
try_connect= 0;
break;
case SSL_ERROR_WANT_WRITE:
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, mysql->options.connect_timeout) < 1)
try_connect= 0;
break;
default:
try_connect= 0;
}
}
/* In case handshake failed or if a root certificate (ca) was specified,
we need to check the result code of X509 verification. A detailed check
of the peer certificate (hostname checking will follow later) */
if (rc != 1 ||
(mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) ||
(mysql->options.ssl_ca || mysql->options.ssl_capath))
{
long x509_err= SSL_get_verify_result(ssl);
if (x509_err != X509_V_OK)
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR), X509_verify_cert_error_string(x509_err));
/* restore blocking mode */
if (!blocking)
pvio->methods->blocking(pvio, FALSE, 0);
return 1;
} else if (rc != 1) {
ma_tls_set_error(mysql);
return 1;
}
}
pvio->ctls->ssl= ctls->ssl= (void *)ssl;
return 0;
}
static my_bool
ma_tls_async_check_result(int res, struct mysql_async_context *b, SSL *ssl)
{
int ssl_err;
b->events_to_wait_for= 0;
if (res >= 0)
return 1;
ssl_err= SSL_get_error(ssl, res);
if (ssl_err == SSL_ERROR_WANT_READ)
b->events_to_wait_for|= MYSQL_WAIT_READ;
else if (ssl_err == SSL_ERROR_WANT_WRITE)
b->events_to_wait_for|= MYSQL_WAIT_WRITE;
else
return 1;
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
return 0;
}
ssize_t ma_tls_read_async(MARIADB_PVIO *pvio,
const unsigned char *buffer,
size_t length)
{
int res;
struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
MARIADB_TLS *ctls= pvio->ctls;
for (;;)
{
res= SSL_read((SSL *)ctls->ssl, (void *)buffer, (int)length);
if (ma_tls_async_check_result(res, b, (SSL *)ctls->ssl))
return res;
}
}
ssize_t ma_tls_write_async(MARIADB_PVIO *pvio,
const unsigned char *buffer,
size_t length)
{
int res;
struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
MARIADB_TLS *ctls= pvio->ctls;
for (;;)
{
res= SSL_write((SSL *)ctls->ssl, (void *)buffer, (int)length);
if (ma_tls_async_check_result(res, b, (SSL *)ctls->ssl))
return res;
}
}
ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
int rc;
MARIADB_PVIO *pvio= ctls->pvio;
while ((rc= SSL_read((SSL *)ctls->ssl, (void *)buffer, (int)length)) < 0)
{
int error= SSL_get_error((SSL *)ctls->ssl, rc);
if (error != SSL_ERROR_WANT_READ)
return rc;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.read_timeout) < 1)
return rc;
}
return rc;
}
ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
int rc;
MARIADB_PVIO *pvio= ctls->pvio;
while ((rc= SSL_write((SSL *)ctls->ssl, (void *)buffer, (int)length)) <= 0)
{
int error= SSL_get_error((SSL *)ctls->ssl, rc);
if (error != SSL_ERROR_WANT_WRITE)
return rc;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.write_timeout) < 1)
return rc;
}
return rc;
}
my_bool ma_tls_close(MARIADB_TLS *ctls)
{
int i, rc;
SSL *ssl;
SSL_CTX *ctx= NULL;
if (!ctls || !ctls->ssl)
return 1;
ssl= (SSL *)ctls->ssl;
ctx= SSL_get_SSL_CTX(ssl);
if (ctx)
SSL_CTX_free(ctx);
SSL_set_quiet_shutdown(ssl, 1);
/* 2 x pending + 2 * data = 4 */
for (i=0; i < 4; i++)
if ((rc= SSL_shutdown(ssl)))
break;
/* Since we transferred ownership of BIO to ssl, BIO will
automatically freed - no need for an explicit BIO_free_all */
SSL_free(ssl);
ctls->ssl= NULL;
return rc;
}
int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
{
X509 *cert;
MYSQL *mysql;
SSL *ssl;
MARIADB_PVIO *pvio;
#if !defined(HAVE_OPENSSL_CHECK_HOST)
X509_NAME *x509sn;
int cn_pos;
X509_NAME_ENTRY *cn_entry;
ASN1_STRING *cn_asn1;
const char *cn_str;
#endif
if (!ctls || !ctls->ssl)
return 1;
ssl= (SSL *)ctls->ssl;
mysql= (MYSQL *)SSL_get_app_data(ssl);
pvio= mysql->net.pvio;
if (!mysql->host)
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR), "Invalid (empty) hostname");
return 1;
}
if (!(cert= SSL_get_peer_certificate(ssl)))
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR), "Unable to get server certificate");
return 1;
}
#ifdef HAVE_OPENSSL_CHECK_HOST
if (X509_check_host(cert, mysql->host, 0, 0, 0) != 1
&& X509_check_ip_asc(cert, mysql->host, 0) != 1)
goto error;
#else
x509sn= X509_get_subject_name(cert);
if ((cn_pos= X509_NAME_get_index_by_NID(x509sn, NID_commonName, -1)) < 0)
goto error;
if (!(cn_entry= X509_NAME_get_entry(x509sn, cn_pos)))
goto error;
if (!(cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry)))
goto error;
cn_str = (char *)ASN1_STRING_data(cn_asn1);
/* Make sure there is no embedded \0 in the CN */
if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn_str))
goto error;
if (strcmp(cn_str, mysql->host))
goto error;
#endif
X509_free(cert);
return 0;
error:
X509_free(cert);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR), "Validation of SSL server certificate failed");
return 1;
}
const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
{
if (!ctls || !ctls->ssl)
return NULL;
return SSL_get_cipher_name(ctls->ssl);
}
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
{
X509 *cert= NULL;
MYSQL *mysql;
unsigned int fp_len;
if (!ctls || !ctls->ssl)
return 0;
mysql= SSL_get_app_data(ctls->ssl);
if (!(cert= SSL_get_peer_certificate(ctls->ssl)))
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Unable to get server certificate");
goto end;
}
if (len < EVP_MAX_MD_SIZE)
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Finger print buffer too small");
goto end;
}
if (!X509_digest(cert, EVP_sha1(), (unsigned char *)fp, &fp_len))
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"invalid finger print of server certificate");
goto end;
}
X509_free(cert);
return (fp_len);
end:
X509_free(cert);
return 0;
}
int ma_tls_get_protocol_version(MARIADB_TLS *ctls)
{
if (!ctls || !ctls->ssl)
return -1;
return SSL_version(ctls->ssl) & 0xFF;
}

View File

@ -0,0 +1,88 @@
/*
Copyright (C) 2018 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*/
#include <ma_global.h>
#include <ma_crypt.h>
#include <openssl/evp.h>
static const EVP_MD *ma_hash_get_algorithm(unsigned int alg)
{
switch(alg)
{
case MA_HASH_MD5:
return EVP_md5();
case MA_HASH_SHA1:
return EVP_sha1();
case MA_HASH_SHA224:
return EVP_sha224();
case MA_HASH_SHA256:
return EVP_sha256();
case MA_HASH_SHA384:
return EVP_sha384();
case MA_HASH_SHA512:
return EVP_sha512();
case MA_HASH_RIPEMD160:
return EVP_ripemd160();
default:
return NULL;
}
}
MA_HASH_CTX *ma_hash_new(unsigned int algorithm, MA_HASH_CTX *unused __attribute__((unused)))
{
EVP_MD_CTX *ctx= NULL;
const EVP_MD *evp_md= ma_hash_get_algorithm(algorithm);
/* unknown or unsupported hash algorithm */
if (!evp_md)
return NULL;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
if (!(ctx= EVP_MD_CTX_new()))
#else
if (!(ctx= EVP_MD_CTX_create()))
#endif
return NULL;
if (!EVP_DigestInit(ctx, evp_md))
{
ma_hash_free(ctx);
return NULL;
}
return ctx;
}
void ma_hash_free(MA_HASH_CTX *ctx)
{
if (ctx)
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
EVP_MD_CTX_free(ctx);
#else
EVP_MD_CTX_destroy(ctx);
#endif
}
void ma_hash_input(MA_HASH_CTX *ctx,
const unsigned char *buffer,
size_t len)
{
EVP_DigestUpdate(ctx, buffer, len);
}
void ma_hash_result(MA_HASH_CTX *ctx, unsigned char *digest)
{
EVP_DigestFinal_ex(ctx, digest, NULL);
}

562
vendor/MDBC/libmariadb/secure/schannel.c vendored Normal file
View File

@ -0,0 +1,562 @@
/************************************************************************************
Copyright (C) 2014 MariaDB Corporation Ab
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include "ma_schannel.h"
#include "schannel_certs.h"
#include <string.h>
extern my_bool ma_tls_initialized;
char tls_library_version[] = "Schannel";
#define PROT_SSL3 1
#define PROT_TLS1_0 2
#define PROT_TLS1_2 4
#define PROT_TLS1_3 8
static struct
{
DWORD cipher_id;
DWORD protocol;
const char *iana_name;
const char *openssl_name;
ALG_ID algs[4]; /* exchange, encryption, hash, signature */
}
cipher_map[] =
{
{
0x0002,
PROT_TLS1_0 | PROT_TLS1_2 | PROT_SSL3,
"TLS_RSA_WITH_NULL_SHA", "NULL-SHA",
{ CALG_RSA_KEYX, 0, CALG_SHA1, CALG_RSA_SIGN }
},
{
0x0004,
PROT_TLS1_0 | PROT_TLS1_2 | PROT_SSL3,
"TLS_RSA_WITH_RC4_128_MD5", "RC4-MD5",
{ CALG_RSA_KEYX, CALG_RC4, CALG_MD5, CALG_RSA_SIGN }
},
{
0x0005,
PROT_TLS1_0 | PROT_TLS1_2 | PROT_SSL3,
"TLS_RSA_WITH_RC4_128_SHA", "RC4-SHA",
{ CALG_RSA_KEYX, CALG_RC4, CALG_SHA1, CALG_RSA_SIGN }
},
{
0x000A,
PROT_SSL3,
"TLS_RSA_WITH_3DES_EDE_CBC_SHA", "DES-CBC3-SHA",
{CALG_RSA_KEYX, CALG_3DES, CALG_SHA1, CALG_DSS_SIGN}
},
{
0x0013,
PROT_TLS1_0 | PROT_TLS1_2 | PROT_SSL3,
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "EDH-DSS-DES-CBC3-SHA",
{ CALG_DH_EPHEM, CALG_3DES, CALG_SHA1, CALG_DSS_SIGN }
},
{
0x002F,
PROT_SSL3 | PROT_TLS1_0 | PROT_TLS1_2,
"TLS_RSA_WITH_AES_128_CBC_SHA", "AES128-SHA",
{ CALG_RSA_KEYX, CALG_AES_128, CALG_SHA, CALG_RSA_SIGN}
},
{
0x0032,
PROT_TLS1_0 | PROT_TLS1_2,
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DHE-DSS-AES128-SHA",
{ CALG_DH_EPHEM, CALG_AES_128, CALG_SHA1, CALG_RSA_SIGN }
},
{
0x0033,
PROT_TLS1_0 | PROT_TLS1_2,
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DHE-RSA-AES128-SHA",
{ CALG_DH_EPHEM, CALG_AES_128, CALG_SHA1, CALG_RSA_SIGN }
},
{
0x0035,
PROT_TLS1_0 | PROT_TLS1_2,
"TLS_RSA_WITH_AES_256_CBC_SHA", "AES256-SHA",
{ CALG_RSA_KEYX, CALG_AES_256, CALG_SHA1, CALG_RSA_SIGN }
},
{
0x0038,
PROT_TLS1_0 | PROT_TLS1_2,
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DHE-DSS-AES256-SHA",
{ CALG_DH_EPHEM, CALG_AES_256, CALG_SHA1, CALG_DSS_SIGN }
},
{
0x0039,
PROT_TLS1_0 | PROT_TLS1_2,
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DHE-RSA-AES256-SHA",
{ CALG_DH_EPHEM, CALG_AES_256, CALG_SHA1, CALG_RSA_SIGN }
},
{
0x003B,
PROT_TLS1_2,
"TLS_RSA_WITH_NULL_SHA256", "NULL-SHA256",
{ CALG_RSA_KEYX, 0, CALG_SHA_256, CALG_RSA_SIGN }
},
{
0x003C,
PROT_TLS1_2,
"TLS_RSA_WITH_AES_128_CBC_SHA256", "AES128-SHA256",
{ CALG_RSA_KEYX, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
},
{
0x003D,
PROT_TLS1_2,
"TLS_RSA_WITH_AES_256_CBC_SHA256", "AES256-SHA256",
{ CALG_RSA_KEYX, CALG_AES_256, CALG_SHA_256, CALG_RSA_SIGN }
},
{
0x0040,
PROT_TLS1_2,
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DHE-DSS-AES128-SHA256",
{ CALG_DH_EPHEM, CALG_AES_128, CALG_SHA_256, CALG_DSS_SIGN }
},
{
0x009C,
PROT_TLS1_2,
"TLS_RSA_WITH_AES_128_GCM_SHA256", "AES128-GCM-SHA256",
{ CALG_RSA_KEYX, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
},
{
0x009D,
PROT_TLS1_2,
"TLS_RSA_WITH_AES_256_GCM_SHA384", "AES256-GCM-SHA384",
{ CALG_RSA_KEYX, CALG_AES_256, CALG_SHA_384, CALG_RSA_SIGN }
},
{
0x009E,
PROT_TLS1_2,
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DHE-RSA-AES128-GCM-SHA256",
{ CALG_DH_EPHEM, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
},
{
0x009F,
PROT_TLS1_2,
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DHE-RSA-AES256-GCM-SHA384",
{ CALG_DH_EPHEM, CALG_AES_256, CALG_SHA_384, CALG_RSA_SIGN }
},
{
0xC027,
PROT_TLS1_2,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDHE-RSA-AES128-SHA256",
{ CALG_ECDH, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
},
{
0xC028,
PROT_TLS1_2,
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDHE-RSA-AES256-SHA384",
{ CALG_ECDH, CALG_AES_256, CALG_SHA_384, CALG_RSA_SIGN }
}
};
#define MAX_ALG_ID 50
extern void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
/*
Initializes SSL and allocate global
context SSL_context
SYNOPSIS
ma_tls_start
RETURN VALUES
0 success
1 error
*/
int ma_tls_start(char *errmsg, size_t errmsg_len)
{
ma_tls_initialized = TRUE;
return 0;
}
/*
Release SSL and free resources
Will be automatically executed by
mysql_server_end() function
SYNOPSIS
ma_tls_end()
void
RETURN VALUES
void
*/
void ma_tls_end()
{
return;
}
/* {{{ static int ma_tls_set_client_certs(MARIADB_TLS *ctls) */
static int ma_tls_set_client_certs(MARIADB_TLS *ctls,const CERT_CONTEXT **cert_ctx)
{
MYSQL *mysql= ctls->pvio->mysql;
char *certfile= mysql->options.ssl_cert,
*keyfile= mysql->options.ssl_key;
MARIADB_PVIO *pvio= ctls->pvio;
char errmsg[256];
if (!certfile && keyfile)
certfile= keyfile;
if (!keyfile && certfile)
keyfile= certfile;
if (!certfile)
return 0;
*cert_ctx = schannel_create_cert_context(certfile, keyfile, errmsg, sizeof(errmsg));
if (!*cert_ctx)
{
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: %s", errmsg);
return 1;
}
return 0;
}
/* }}} */
/* {{{ void *ma_tls_init(MARIADB_TLS *ctls, MYSQL *mysql) */
void *ma_tls_init(MYSQL *mysql)
{
SC_CTX *sctx = (SC_CTX *)LocalAlloc(LMEM_ZEROINIT, sizeof(SC_CTX));
if (sctx)
{
SecInvalidateHandle(&sctx->CredHdl);
SecInvalidateHandle(&sctx->hCtxt);
}
return sctx;
}
/* }}} */
/*
Maps between openssl suite names and schannel alg_ids.
Every suite has 4 algorithms (for exchange, encryption, hash and signing).
The input string is a set of suite names (openssl), separated
by ':'
The output is written into the array 'arr' of size 'arr_size'
The function returns number of elements written to the 'arr'.
*/
static struct _tls_version {
const char *tls_version;
DWORD protocol;
} tls_version[]= {
{"TLSv1.0", PROT_TLS1_0},
{"TLSv1.2", PROT_TLS1_2},
{"TLSv1.3", PROT_TLS1_3},
{"SSLv3", PROT_SSL3}
};
/* The following list was produced with OpenSSL 1.1.1j
by executing `openssl ciphers -V`. */
static struct {
DWORD dwCipherSuite;
const char *openssl_name;
} openssl_ciphers[] = {
{0x002F, "AES128-SHA"},
{0x0033, "DHE-RSA-AES128-SHA"},
{0x0035, "AES256-SHA"},
{0x0039, "DHE-RSA-AES256-SHA"},
{0x003C, "AES128-SHA256"},
{0x003D, "AES256-SHA256"},
{0x0067, "DHE-RSA-AES128-SHA256"},
{0x006B, "DHE-RSA-AES256-SHA256"},
{0x008C, "PSK-AES128-CBC-SHA"},
{0x008D, "PSK-AES256-CBC-SHA"},
{0x0090, "DHE-PSK-AES128-CBC-SHA"},
{0x0091, "DHE-PSK-AES256-CBC-SHA"},
{0x0094, "RSA-PSK-AES128-CBC-SHA"},
{0x0095, "RSA-PSK-AES256-CBC-SHA"},
{0x009C, "AES128-GCM-SHA256"},
{0x009D, "AES256-GCM-SHA384"},
{0x009E, "DHE-RSA-AES128-GCM-SHA256"},
{0x009F, "DHE-RSA-AES256-GCM-SHA384"},
{0x00A8, "PSK-AES128-GCM-SHA256"},
{0x00A9, "PSK-AES256-GCM-SHA384"},
{0x00AA, "DHE-PSK-AES128-GCM-SHA256"},
{0x00AB, "DHE-PSK-AES256-GCM-SHA384"},
{0x00AC, "RSA-PSK-AES128-GCM-SHA256"},
{0x00AD, "RSA-PSK-AES256-GCM-SHA384"},
{0x00AE, "PSK-AES128-CBC-SHA256"},
{0x00AF, "PSK-AES256-CBC-SHA384"},
{0x00B2, "DHE-PSK-AES128-CBC-SHA256"},
{0x00B3, "DHE-PSK-AES256-CBC-SHA384"},
{0x00B6, "RSA-PSK-AES128-CBC-SHA256"},
{0x00B7, "RSA-PSK-AES256-CBC-SHA384"},
{0x1301, "TLS_AES_128_GCM_SHA256"},
{0x1302, "TLS_AES_256_GCM_SHA384"},
{0x1303, "TLS_CHACHA20_POLY1305_SHA256"},
{0xC009, "ECDHE-ECDSA-AES128-SHA"},
{0xC00A, "ECDHE-ECDSA-AES256-SHA"},
{0xC013, "ECDHE-RSA-AES128-SHA"},
{0xC014, "ECDHE-RSA-AES256-SHA"},
{0xC01D, "SRP-AES-128-CBC-SHA"},
{0xC01E, "SRP-RSA-AES-128-CBC-SHA"},
{0xC020, "SRP-AES-256-CBC-SHA"},
{0xC021, "SRP-RSA-AES-256-CBC-SHA"},
{0xC023, "ECDHE-ECDSA-AES128-SHA256"},
{0xC024, "ECDHE-ECDSA-AES256-SHA384"},
{0xC027, "ECDHE-RSA-AES128-SHA256"},
{0xC028, "ECDHE-RSA-AES256-SHA384"},
{0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"},
{0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"},
{0xC02F, "ECDHE-RSA-AES128-GCM-SHA256"},
{0xC030, "ECDHE-RSA-AES256-GCM-SHA384"},
{0xC035, "ECDHE-PSK-AES128-CBC-SHA"},
{0xC036, "ECDHE-PSK-AES256-CBC-SHA"},
{0xC037, "ECDHE-PSK-AES128-CBC-SHA256"},
{0xC038, "ECDHE-PSK-AES256-CBC-SHA384"},
{0xCCA8, "ECDHE-RSA-CHACHA20-POLY1305"},
{0xCCA9, "ECDHE-ECDSA-CHACHA20-POLY1305"},
{0xCCAA, "DHE-RSA-CHACHA20-POLY1305"},
{0xCCAB, "PSK-CHACHA20-POLY1305"},
{0xCCAC, "ECDHE-PSK-CHACHA20-POLY1305"},
{0xCCAD, "DHE-PSK-CHACHA20-POLY1305"},
{0xCCAE, "RSA-PSK-CHACHA20-POLY1305"}
};
static size_t set_cipher(char * cipher_str, DWORD protocol, ALG_ID *arr , size_t arr_size)
{
char *token = strtok(cipher_str, ":");
size_t pos = 0;
while (token)
{
size_t i;
for(i = 0; i < sizeof(cipher_map)/sizeof(cipher_map[0]) ; i++)
{
if((pos + 4 < arr_size && strcmp(cipher_map[i].openssl_name, token) == 0) ||
(cipher_map[i].protocol <= protocol))
{
memcpy(arr + pos, cipher_map[i].algs, sizeof(ALG_ID)* 4);
pos += 4;
break;
}
}
token = strtok(NULL, ":");
}
return pos;
}
my_bool ma_tls_connect(MARIADB_TLS *ctls)
{
MYSQL *mysql;
SCHANNEL_CRED Cred = {0};
MARIADB_PVIO *pvio;
my_bool rc= 1;
SC_CTX *sctx;
SECURITY_STATUS sRet;
ALG_ID AlgId[MAX_ALG_ID];
size_t i;
DWORD protocol = 0;
int verify_certs;
const CERT_CONTEXT* cert_context = NULL;
if (!ctls)
return 1;
pvio= ctls->pvio;
sctx= (SC_CTX *)ctls->ssl;
if (!pvio || !sctx)
return 1;
mysql= pvio->mysql;
if (!mysql)
return 1;
/* Set cipher */
if (mysql->options.ssl_cipher)
{
/* check if a protocol was specified as a cipher:
* In this case don't allow cipher suites which belong to newer protocols
* Please note: There are no cipher suites for TLS1.1
*/
for (i = 0; i < sizeof(tls_version) / sizeof(tls_version[0]); i++)
{
if (!_stricmp(mysql->options.ssl_cipher, tls_version[i].tls_version))
protocol |= tls_version[i].protocol;
}
memset(AlgId, 0, sizeof(AlgId));
Cred.cSupportedAlgs = (DWORD)set_cipher(mysql->options.ssl_cipher, protocol, AlgId, MAX_ALG_ID);
if (Cred.cSupportedAlgs)
{
Cred.palgSupportedAlgs = AlgId;
}
else if (!protocol)
{
ma_schannel_set_sec_error(pvio, SEC_E_ALGORITHM_MISMATCH);
goto end;
}
}
Cred.dwVersion= SCHANNEL_CRED_VERSION;
Cred.dwFlags = SCH_CRED_NO_SERVERNAME_CHECK | SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
if (mysql->options.extension && mysql->options.extension->tls_version)
{
if (strstr(mysql->options.extension->tls_version, "TLSv1.0"))
Cred.grbitEnabledProtocols|= SP_PROT_TLS1_0_CLIENT;
if (strstr(mysql->options.extension->tls_version, "TLSv1.1"))
Cred.grbitEnabledProtocols|= SP_PROT_TLS1_1_CLIENT;
if (strstr(mysql->options.extension->tls_version, "TLSv1.2"))
Cred.grbitEnabledProtocols|= SP_PROT_TLS1_2_CLIENT;
}
if (!Cred.grbitEnabledProtocols)
Cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
if (ma_tls_set_client_certs(ctls, &cert_context))
goto end;
if (cert_context)
{
Cred.cCreds = 1;
Cred.paCred = &cert_context;
}
sRet= AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND,
NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL);
if (sRet)
{
ma_schannel_set_sec_error(pvio, sRet);
goto end;
}
if (ma_schannel_client_handshake(ctls) != SEC_E_OK)
goto end;
verify_certs = mysql->options.ssl_ca || mysql->options.ssl_capath ||
(mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT);
if (verify_certs)
{
if (!ma_schannel_verify_certs(ctls, (mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT)))
goto end;
}
rc = 0;
end:
if (cert_context)
schannel_free_cert_context(cert_context);
return rc;
}
ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
MARIADB_PVIO *pvio= ctls->pvio;
DWORD dlength= 0;
SECURITY_STATUS status = ma_schannel_read_decrypt(pvio, &sctx->hCtxt, &dlength, (uchar *)buffer, (DWORD)length);
if (status == SEC_I_CONTEXT_EXPIRED)
return 0; /* other side shut down the connection. */
if (status == SEC_I_RENEGOTIATE)
return -1; /* Do not handle renegotiate yet */
return (status == SEC_E_OK)? (ssize_t)dlength : -1;
}
ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
MARIADB_PVIO *pvio= ctls->pvio;
ssize_t rc, wlength= 0;
ssize_t remain= length;
while (remain > 0)
{
if ((rc= ma_schannel_write_encrypt(pvio, (uchar *)buffer + wlength, remain)) <= 0)
return rc;
wlength+= rc;
remain-= rc;
}
return length;
}
/* {{{ my_bool ma_tls_close(MARIADB_PVIO *pvio) */
my_bool ma_tls_close(MARIADB_TLS *ctls)
{
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
if (sctx)
{
LocalFree(sctx->IoBuffer);
if (SecIsValidHandle(&sctx->CredHdl))
FreeCredentialHandle(&sctx->CredHdl);
if (SecIsValidHandle(&sctx->hCtxt))
DeleteSecurityContext(&sctx->hCtxt);
}
LocalFree(sctx);
return 0;
}
/* }}} */
int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
{
/* Done elsewhere */
return 0;
}
static const char *cipher_name(const SecPkgContext_CipherInfo *CipherInfo)
{
size_t i;
for(i = 0; i < sizeof(openssl_ciphers)/sizeof(openssl_ciphers[0]) ; i++)
{
if (CipherInfo->dwCipherSuite == openssl_ciphers[i].dwCipherSuite)
return openssl_ciphers[i].openssl_name;
}
return "";
};
const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
{
SecPkgContext_CipherInfo CipherInfo = { SECPKGCONTEXT_CIPHERINFO_V1 };
SECURITY_STATUS sRet;
SC_CTX *sctx;
if (!ctls || !ctls->ssl)
return NULL;
sctx= (SC_CTX *)ctls->ssl;
sRet= QueryContextAttributesA(&sctx->hCtxt, SECPKG_ATTR_CIPHER_INFO, (PVOID)&CipherInfo);
if (sRet != SEC_E_OK)
return NULL;
return cipher_name(&CipherInfo);
}
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
{
SC_CTX *sctx= (SC_CTX *)ctls->ssl;
PCCERT_CONTEXT pRemoteCertContext = NULL;
if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK)
return 0;
CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, (DWORD *)&len);
CertFreeCertificateContext(pRemoteCertContext);
return len;
}

View File

@ -0,0 +1,854 @@
/************************************************************************************
Copyright (C) 2019 MariaDB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
/*
This module contain X509 certificate handling on Windows.
PEM parsing, loading client certificate and key, server certificate validation
*/
/*
CERT_CHAIN_ENGINE_CONFIG has additional members in Windows 8.1
To allow client to be work on pre-8.1 Windows, compile
with corresponding _WIN32_WINNT
*/
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0601
#endif
#include <winsock2.h>
#include "schannel_certs.h"
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <ws2tcpip.h>
#include <winhttp.h>
#include <assert.h>
#include "win32_errmsg.h"
/*
Return GetLastError(), or, if this unexpectedly gives success,
return ERROR_INTERNAL_ERROR.
Background - in several cases in this module we return GetLastError()
after an Windows function fails. However, we do not want the function to
return success, even if GetLastError() was suddenly 0.
*/
static DWORD get_last_error()
{
DWORD ret = GetLastError();
if (ret)
return ret;
// We generally expect last error to be set API fails.
// thus the debug assertion-
assert(0);
return ERROR_INTERNAL_ERROR;
}
#define FAIL(...) \
do{\
status = get_last_error();\
ma_format_win32_error(errmsg, errmsg_len, status, __VA_ARGS__);\
goto cleanup;\
} while (0)
/*
Load file into memory. Add null terminator at the end, so it will be a valid C string.
*/
static char* pem_file_to_string(const char* file, char* errmsg, size_t errmsg_len)
{
LARGE_INTEGER file_size;
size_t file_bufsize = 0;
size_t total_bytes_read = 0;
char* file_buffer = NULL;
SECURITY_STATUS status = SEC_E_OK;
HANDLE file_handle = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle == INVALID_HANDLE_VALUE)
{
FAIL("failed to open file '%s'", file);
}
if (!GetFileSizeEx(file_handle, &file_size))
{
FAIL("GetFileSizeEx failed on '%s'", file);
}
if (file_size.QuadPart > ULONG_MAX - 1)
{
SetLastError(SEC_E_INVALID_PARAMETER);
FAIL("file '%s' too large", file);
}
file_bufsize = (size_t)file_size.QuadPart;
file_buffer = (char*)LocalAlloc(0,file_bufsize + 1);
if (!file_buffer)
{
FAIL("LocalAlloc(0,%zu) failed", file_bufsize + 1);
}
while (total_bytes_read < file_bufsize)
{
DWORD bytes_to_read = (DWORD)(file_bufsize - total_bytes_read);
DWORD bytes_read = 0;
if (!ReadFile(file_handle, file_buffer + total_bytes_read,
bytes_to_read, &bytes_read, NULL))
{
FAIL("ReadFile() failed to read file '%s'", file);
}
if (bytes_read == 0)
{
/* Premature EOF -- adjust the bufsize to the new value */
file_bufsize = total_bytes_read;
}
else
{
total_bytes_read += bytes_read;
}
}
/* Null terminate the buffer */
file_buffer[file_bufsize] = '\0';
cleanup:
if (file_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(file_handle);
}
if (status)
{
/* Some error happened. */
LocalFree(file_buffer);
file_buffer = NULL;
}
return file_buffer;
}
// Structure for parsing BEGIN/END sections inside pem.
typedef struct _pem_type_desc
{
const char* begin_tag;
size_t begin_tag_len;
const char* end_tag;
size_t end_tag_len;
} pem_type_desc;
#define BEGIN_TAG(x) "-----BEGIN " x "-----"
#define END_TAG(x) "\n-----END " x "-----"
#define PEM_SECTION(tag) {BEGIN_TAG(tag), sizeof(BEGIN_TAG(tag))-1, END_TAG(tag), sizeof(END_TAG(tag))-1}
typedef enum {
PEM_TYPE_CERTIFICATE = 0,
PEM_TYPE_X509_CRL,
PEM_TYPE_RSA_PRIVATE_KEY,
PEM_TYPE_PRIVATE_KEY
} PEM_TYPE;
static const pem_type_desc pem_sections[] = {
PEM_SECTION("CERTIFICATE"),
PEM_SECTION("X509 CRL"),
PEM_SECTION("RSA PRIVATE KEY"),
PEM_SECTION("PRIVATE KEY")
};
/*
Locate a substring in pem for given type,
e.g section between BEGIN CERTIFICATE and END CERTIFICATE
in PEMs base64 format, with header and footer.
output parameters 'begin' and 'end' are set upon return.
it is possible that functions returns 'begin' != NULL but
'end' = NULL. This is generally a format error, meaning that
the end tag was not found
*/
void pem_locate(char* pem_str,
PEM_TYPE type,
char** begin,
char** end)
{
*begin = NULL;
*end = NULL;
char c;
const pem_type_desc* desc = &pem_sections[type];
*begin = strstr(pem_str, desc->begin_tag);
if (!(*begin))
return;
// We expect newline after the
// begin tag, LF or CRLF
c = (*begin)[desc->begin_tag_len];
if (c != '\r' && c != '\n')
{
*begin = NULL;
return;
}
*end = strstr(*begin + desc->begin_tag_len + 1, desc->end_tag);
if (!*end)
return; // error, end marker not found
(*end) += desc->end_tag_len;
return;
}
/*
Add certificates, or CRLs from a PEM file to Wincrypt store
*/
static SECURITY_STATUS add_certs_to_store(
HCERTSTORE trust_store,
const char* file,
PEM_TYPE type,
char* errmsg,
size_t errmsg_len)
{
char* file_buffer = NULL;
char* cur = NULL;
SECURITY_STATUS status = SEC_E_OK;
CRL_CONTEXT* crl_context = NULL;
CERT_CONTEXT* cert_context = NULL;
char* begin;
char* end;
file_buffer = pem_file_to_string(file, errmsg, errmsg_len);
if (!file_buffer)
goto cleanup;
for (cur = file_buffer; ; cur = end)
{
pem_locate(cur, type, &begin, &end);
if (!begin)
break;
if (!end)
{
SetLastError(SEC_E_INVALID_PARAMETER);
FAIL("Invalid PEM file '%s', missing end marker corresponding to begin marker '%s' at offset %zu",
file, pem_sections[type].begin_tag, (size_t)(begin - file_buffer));
}
CERT_BLOB cert_blob;
void* context = NULL;
DWORD actual_content_type = 0;
cert_blob.pbData = (BYTE*)begin;
cert_blob.cbData = (DWORD)(end - begin);
if (!CryptQueryObject(
CERT_QUERY_OBJECT_BLOB, &cert_blob,
CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_CRL,
CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &actual_content_type,
NULL, NULL, NULL, (const void**)&context))
{
FAIL("failed to extract certificate from PEM file '%s'",file);
}
if (!context)
{
SetLastError(SEC_E_INTERNAL_ERROR);
FAIL("unexpected result from CryptQueryObject(),cert_context is NULL"
" after successful completion, file '%s'",
file);
}
if (actual_content_type == CERT_QUERY_CONTENT_CERT)
{
CERT_CONTEXT* cert_context = (CERT_CONTEXT*)context;
if (!CertAddCertificateContextToStore(
trust_store, cert_context,
CERT_STORE_ADD_ALWAYS, NULL))
{
FAIL("CertAddCertificateContextToStore failed");
}
}
else if (actual_content_type == CERT_QUERY_CONTENT_CRL)
{
CRL_CONTEXT* crl_context = (CRL_CONTEXT*)context;
if (!CertAddCRLContextToStore(
trust_store, crl_context,
CERT_STORE_ADD_ALWAYS, NULL))
{
FAIL("CertAddCRLContextToStore() failed");
}
}
}
cleanup:
LocalFree(file_buffer);
if (cert_context)
CertFreeCertificateContext(cert_context);
if (crl_context)
CertFreeCRLContext(crl_context);
return status;
}
/*
Add a directory to store, i.e try to load all files.
(extract certificates and add them to store)
@return 0 on success, error only if directory is invalid.
*/
SECURITY_STATUS add_dir_to_store(HCERTSTORE trust_store, const char* dir,
PEM_TYPE type, char* errmsg, size_t errmsg_len)
{
WIN32_FIND_DATAA ffd;
char path[MAX_PATH];
char pattern[MAX_PATH];
DWORD dwAttr;
HANDLE hFind = INVALID_HANDLE_VALUE;
SECURITY_STATUS status = SEC_E_OK;
if ((dwAttr = GetFileAttributes(dir)) == INVALID_FILE_ATTRIBUTES)
{
SetLastError(SEC_E_INVALID_PARAMETER);
FAIL("directory '%s' does not exist", dir);
}
if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
{
SetLastError(SEC_E_INVALID_PARAMETER);
FAIL("'%s' is not a directory", dir);
}
sprintf_s(pattern, sizeof(pattern), "%s\\*", dir);
hFind = FindFirstFile(pattern, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
FAIL("FindFirstFile(%s) failed",pattern);
}
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
sprintf_s(path, sizeof(path), "%s\\%s", dir, ffd.cFileName);
// ignore error from add_certs_to_store(), not all file
// maybe PEM.
add_certs_to_store(trust_store, path, type, errmsg,
errmsg_len);
} while (FindNextFile(hFind, &ffd) != 0);
cleanup:
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
return status;
}
/* Count certificates in store. */
static int count_certificates(HCERTSTORE store)
{
int num_certs = 0;
PCCERT_CONTEXT c = NULL;
while ((c = CertEnumCertificatesInStore(store, c)))
num_certs++;
return num_certs;
}
/**
Creates certificate store with user defined CA chain and/or CRL.
Loads PEM certificate from files or directories.
If only CRLFile/CRLPath is defined, the "system" store is duplicated,
and new CRLs are added to it.
If CAFile/CAPAth is defined, then new empty store is created, and CAs
(and CRLs, if defined), are added to it.
The function throws an error, if none of the files in CAFile/CAPath have a valid certificate.
It is also an error if CRLFile does not exist.
*/
SECURITY_STATUS schannel_create_store(
const char* CAFile,
const char* CAPath,
const char* CRLFile,
const char* CRLPath,
HCERTSTORE* out_store,
char* errmsg,
size_t errmsg_len)
{
HCERTSTORE store = NULL;
HCERTSTORE system_store = NULL;
int status = SEC_E_OK;
*out_store = NULL;
if (!CAFile && !CAPath && !CRLFile && !CRLPath)
{
/* Nothing to do, caller will use default store*/
*out_store = NULL;
return SEC_E_OK;
}
if (CAFile || CAPath)
{
/* Open the certificate store */
store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, (HCRYPTPROV)NULL,
CERT_STORE_CREATE_NEW_FLAG, NULL);
if (!store)
{
FAIL("CertOpenStore failed for memory store");
}
}
else if (CRLFile || CRLPath)
{
/* Only CRL was provided, copy system store, add revocation list to
* it. */
system_store =
CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, (HCRYPTPROV_LEGACY)NULL,
CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if (!system_store)
{
FAIL("CertOpenStore failed for system store");
}
store = CertDuplicateStore(system_store);
if (!store)
{
FAIL("CertDuplicateStore failed");
}
}
if (CAFile)
{
status = add_certs_to_store(store, CAFile,
PEM_TYPE_CERTIFICATE, errmsg, errmsg_len);
if (status)
goto cleanup;
}
if (CAPath)
{
status = add_dir_to_store(store, CAPath,
PEM_TYPE_CERTIFICATE, errmsg, errmsg_len);
if (status)
goto cleanup;
}
if ((CAFile || CAPath) && store && !count_certificates(store))
{
SetLastError(SEC_E_INVALID_PARAMETER);
FAIL("no valid certificates were found, CAFile='%s', CAPath='%s'",
CAFile ? CAFile : "<not set>", CAPath ? CAPath : "<not set>");
}
if (CRLFile)
{
status = add_certs_to_store(store, CRLFile, PEM_TYPE_X509_CRL,
errmsg, errmsg_len);
}
if (CRLPath)
{
status = add_dir_to_store(store, CRLPath, PEM_TYPE_X509_CRL,
errmsg, errmsg_len);
}
cleanup:
if (system_store)
CertCloseStore(system_store, 0);
if (status && store)
{
CertCloseStore(store, 0);
store = NULL;
}
*out_store = store;
return status;
}
/*
The main verification logic.
Taken almost completely from Windows 2003 Platform SDK 2003
(Samples\Security\SSPI\SSL\WebClient.c)
The only difference here is is usage of custom store
and chain engine.
*/
static SECURITY_STATUS VerifyServerCertificate(
PCCERT_CONTEXT pServerCert,
HCERTSTORE hStore,
LPWSTR pwszServerName,
DWORD dwRevocationCheckFlags,
DWORD dwVerifyFlags,
LPSTR errmsg,
size_t errmsg_len)
{
SSL_EXTRA_CERT_CHAIN_POLICY_PARA polExtra;
CERT_CHAIN_POLICY_PARA PolicyPara;
CERT_CHAIN_POLICY_STATUS PolicyStatus;
CERT_CHAIN_PARA ChainPara;
HCERTCHAINENGINE hChainEngine = NULL;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
szOID_SERVER_GATED_CRYPTO,
szOID_SGC_NETSCAPE };
DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
SECURITY_STATUS status = SEC_E_OK;
if (pServerCert == NULL)
{
SetLastError(SEC_E_WRONG_PRINCIPAL);
FAIL("Invalid parameter pServerCert passed to VerifyServerCertificate");
}
ZeroMemory(&ChainPara, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
if (hStore)
{
CERT_CHAIN_ENGINE_CONFIG EngineConfig = { 0 };
EngineConfig.cbSize = sizeof(EngineConfig);
EngineConfig.hExclusiveRoot = hStore;
if (!CertCreateCertificateChainEngine(&EngineConfig, &hChainEngine))
{
FAIL("CertCreateCertificateChainEngine failed");
}
}
if (!CertGetCertificateChain(
hChainEngine,
pServerCert,
NULL,
pServerCert->hCertStore,
&ChainPara,
dwRevocationCheckFlags,
NULL,
&pChainContext))
{
FAIL("CertGetCertificateChain failed");
goto cleanup;
}
// Validate certificate chain.
ZeroMemory(&polExtra, sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
polExtra.cbStruct = sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
polExtra.dwAuthType = AUTHTYPE_SERVER;
polExtra.fdwChecks = dwVerifyFlags;
polExtra.pwszServerName = pwszServerName;
memset(&PolicyPara, 0, sizeof(PolicyPara));
PolicyPara.cbSize = sizeof(PolicyPara);
PolicyPara.pvExtraPolicyPara = &polExtra;
memset(&PolicyStatus, 0, sizeof(PolicyStatus));
PolicyStatus.cbSize = sizeof(PolicyStatus);
if (!CertVerifyCertificateChainPolicy(
CERT_CHAIN_POLICY_SSL,
pChainContext,
&PolicyPara,
&PolicyStatus))
{
FAIL("CertVerifyCertificateChainPolicy failed");
}
if (PolicyStatus.dwError)
{
SetLastError(PolicyStatus.dwError);
FAIL("Server certificate validation failed");
}
cleanup:
if (hChainEngine)
{
CertFreeCertificateChainEngine(hChainEngine);
}
if (pChainContext)
{
CertFreeCertificateChain(pChainContext);
}
return status;
}
void schannel_free_store(HCERTSTORE store)
{
if (store)
CertCloseStore(store, 0);
}
/*
Verify server certificate against a wincrypt store
@return 0 - success, otherwise error occurred.
*/
SECURITY_STATUS schannel_verify_server_certificate(
const CERT_CONTEXT* cert,
HCERTSTORE store,
BOOL check_revocation,
const char* server_name,
BOOL check_server_name,
char* errmsg,
size_t errmsg_len)
{
SECURITY_STATUS status = SEC_E_OK;
wchar_t* wserver_name = NULL;
DWORD dwVerifyFlags;
DWORD dwRevocationFlags;
if (check_server_name)
{
int cchServerName = (int)strlen(server_name) + 1;
wserver_name = (wchar_t*)LocalAlloc(0,sizeof(wchar_t) * cchServerName);
if (!wserver_name)
{
FAIL("LocalAlloc() failed");
}
if (MultiByteToWideChar(CP_UTF8, 0, server_name, cchServerName, wserver_name, cchServerName) < 0)
{
FAIL("MultiByteToWideChar() failed");
}
}
dwVerifyFlags = 0;
dwRevocationFlags = 0;
if (check_revocation)
dwRevocationFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
if (!check_server_name)
dwVerifyFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
status = VerifyServerCertificate(cert, store, wserver_name ? wserver_name : L"SERVER_NAME",
dwRevocationFlags, dwVerifyFlags, errmsg, errmsg_len);
cleanup:
LocalFree(wserver_name);
return status;
}
/* Attach private key (in PEM format) to client certificate */
static SECURITY_STATUS load_private_key(CERT_CONTEXT* cert, char* private_key_str, size_t len, char* errmsg, size_t errmsg_len)
{
DWORD derlen = (DWORD)len;
BYTE* derbuf = NULL;
DWORD keyblob_len = 0;
BYTE* keyblob = NULL;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
CERT_KEY_CONTEXT cert_key_context = { 0 };
PCRYPT_PRIVATE_KEY_INFO pki = NULL;
DWORD pki_len = 0;
SECURITY_STATUS status = SEC_E_OK;
derbuf = LocalAlloc(0, derlen);
if (!derbuf)
{
FAIL("LocalAlloc failed");
}
if (!CryptStringToBinaryA(private_key_str, (DWORD)len, CRYPT_STRING_BASE64HEADER, derbuf, &derlen, NULL, NULL))
{
FAIL("Failed to convert BASE64 private key");
}
/*
To accommodate for both "BEGIN PRIVATE KEY" vs "BEGIN RSA PRIVATE KEY"
sections in PEM, we try to decode with PKCS_PRIVATE_KEY_INFO first,
and, if it fails, with PKCS_RSA_PRIVATE_KEY flag.
*/
if (CryptDecodeObjectEx(
X509_ASN_ENCODING,
PKCS_PRIVATE_KEY_INFO,
derbuf, derlen,
CRYPT_DECODE_ALLOC_FLAG,
NULL, &pki, &pki_len))
{
// convert private key info to RSA private key blob
if (!CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_RSA_PRIVATE_KEY,
pki->PrivateKey.pbData,
pki->PrivateKey.cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL, &keyblob, &keyblob_len))
{
FAIL("Failed to parse private key");
}
}
else if (!CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_RSA_PRIVATE_KEY,
derbuf, derlen,
CRYPT_DECODE_ALLOC_FLAG, NULL,
&keyblob, &keyblob_len))
{
FAIL("Failed to parse private key");
}
if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
FAIL("CryptAcquireContext failed");
}
if (!CryptImportKey(hProv, keyblob, keyblob_len, 0, 0, (HCRYPTKEY*)&hKey))
{
FAIL("CryptImportKey failed");
}
cert_key_context.hCryptProv = hProv;
cert_key_context.dwKeySpec = AT_KEYEXCHANGE;
cert_key_context.cbSize = sizeof(cert_key_context);
/* assign private key to certificate context */
if (!CertSetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
CERT_STORE_NO_CRYPT_RELEASE_FLAG,
&cert_key_context))
{
FAIL("CertSetCertificateContextProperty failed");
}
cleanup:
LocalFree(derbuf);
LocalFree(keyblob);
LocalFree(pki);
if (hKey)
CryptDestroyKey(hKey);
if (status)
{
if (hProv)
CryptReleaseContext(hProv, 0);
}
return status;
}
/*
Given PEM strings for certificate and private key,
create a client certificate*
*/
static CERT_CONTEXT* create_client_certificate_mem(
char* cert_file_content,
char* key_file_content,
char* errmsg,
size_t errmsg_len)
{
CERT_CONTEXT* ctx = NULL;
char* begin;
char* end;
CERT_BLOB cert_blob;
DWORD actual_content_type = 0;
SECURITY_STATUS status = SEC_E_OK;
/* Parse certificate */
pem_locate(cert_file_content, PEM_TYPE_CERTIFICATE,
&begin, &end);
if (!begin || !end)
{
SetLastError(SEC_E_INVALID_PARAMETER);
FAIL("Client certificate not found in PEM file");
}
cert_blob.pbData = (BYTE*)begin;
cert_blob.cbData = (DWORD)(end - begin);
if (!CryptQueryObject(
CERT_QUERY_OBJECT_BLOB, &cert_blob,
CERT_QUERY_CONTENT_FLAG_CERT,
CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &actual_content_type,
NULL, NULL, NULL, (const void**)&ctx))
{
FAIL("Can't parse client certficate");
}
/* Parse key */
PEM_TYPE types[] = { PEM_TYPE_RSA_PRIVATE_KEY, PEM_TYPE_PRIVATE_KEY };
for (int i = 0; i < sizeof(types) / sizeof(types[0]); i++)
{
pem_locate(key_file_content, types[i], &begin, &end);
if (begin && end)
{
/* Assign key to certificate.*/
status = load_private_key(ctx, begin, (end - begin), errmsg, errmsg_len);
goto cleanup;
}
}
if (!begin || !end)
{
SetLastError(SEC_E_INVALID_PARAMETER);
FAIL("Client private key not found in PEM");
}
cleanup:
if (status && ctx)
{
CertFreeCertificateContext(ctx);
ctx = NULL;
}
return ctx;
}
/* Given cert and key, as PEM file names, create a client certificate */
CERT_CONTEXT* schannel_create_cert_context(char* cert_file, char* key_file, char* errmsg, size_t errmsg_len)
{
CERT_CONTEXT* ctx = NULL;
char* key_file_content = NULL;
char* cert_file_content = NULL;
cert_file_content = pem_file_to_string(cert_file, errmsg, errmsg_len);
if (!cert_file_content)
goto cleanup;
if (cert_file == key_file)
{
key_file_content = cert_file_content;
}
else
{
key_file_content = pem_file_to_string(key_file, errmsg, errmsg_len);
if (!key_file_content)
goto cleanup;
}
ctx = create_client_certificate_mem(cert_file_content, key_file_content, errmsg, errmsg_len);
cleanup:
LocalFree(cert_file_content);
if (cert_file != key_file)
LocalFree(key_file_content);
return ctx;
}
/*
Free certificate, and all resources, created by schannel_create_cert_context()
*/
void schannel_free_cert_context(const CERT_CONTEXT* cert)
{
/* release provider handle which was acquires in load_private_key() */
CERT_KEY_CONTEXT cert_key_context = { 0 };
cert_key_context.cbSize = sizeof(cert_key_context);
DWORD cbData = sizeof(CERT_KEY_CONTEXT);
HCRYPTPROV hProv = 0;
if (CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID, &cert_key_context, &cbData))
{
hProv = cert_key_context.hCryptProv;
}
CertFreeCertificateContext(cert);
if (hProv)
{
CryptReleaseContext(cert_key_context.hCryptProv, 0);
}
}

View File

@ -0,0 +1,53 @@
/************************************************************************************
Copyright (C) 2019 MariaDB Corporation Ab
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#pragma once
#include <windows.h>
#include <wincrypt.h>
extern SECURITY_STATUS schannel_create_store(
const char* CAFile,
const char* CAPath,
const char* CRLFile,
const char* CRLPath,
HCERTSTORE* store,
char* errmsg,
size_t errmsg_len
);
extern SECURITY_STATUS schannel_verify_server_certificate(
const CERT_CONTEXT* cert,
HCERTSTORE store,
BOOL check_revocation,
const char* server_name,
BOOL check_server_name,
char* errmsg,
size_t errmsg_len);
extern void schannel_free_store(HCERTSTORE store);
extern CERT_CONTEXT* schannel_create_cert_context(
char* cert_file,
char* key_file,
char* errmsg,
size_t errmsg_len);
extern void schannel_free_cert_context(const CERT_CONTEXT* cert);

View File

@ -0,0 +1,103 @@
/*
Copyright (C) 2018 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*/
#include <windows.h>
#include <bcrypt.h>
#include <ma_crypt.h>
#include <malloc.h>
BCRYPT_ALG_HANDLE Sha256Prov= 0;
BCRYPT_ALG_HANDLE Sha512Prov= 0;
BCRYPT_ALG_HANDLE RsaProv= 0;
static LPCWSTR ma_hash_get_algorithm(unsigned int alg, BCRYPT_ALG_HANDLE *algHdl)
{
switch(alg)
{
case MA_HASH_SHA256:
*algHdl= Sha256Prov;
return BCRYPT_SHA256_ALGORITHM;
case MA_HASH_SHA512:
*algHdl= Sha512Prov;
return BCRYPT_SHA512_ALGORITHM;
default:
*algHdl= 0;
return NULL;
}
}
MA_HASH_CTX *ma_hash_new(unsigned int algorithm, MA_HASH_CTX *ctx)
{
MA_HASH_CTX *newctx= ctx;
DWORD cbObjSize, cbData;
LPCWSTR alg;
BCRYPT_ALG_HANDLE algHdl= 0;
alg= ma_hash_get_algorithm(algorithm, &algHdl);
if (!alg || !algHdl)
return NULL;
if (BCryptGetProperty(algHdl, BCRYPT_OBJECT_LENGTH,
(PBYTE)&cbObjSize, sizeof(DWORD),
&cbData, 0) < 0)
goto error;
if (!newctx)
{
newctx= (MA_HASH_CTX *)calloc(1, sizeof(MA_HASH_CTX));
newctx->free_me= 1;
}
else
memset(newctx, 0, sizeof(MA_HASH_CTX));
newctx->hashObject= (PBYTE)malloc(cbObjSize);
newctx->digest_len= (DWORD)ma_hash_digest_size(algorithm);
BCryptCreateHash(algHdl, &newctx->hHash, newctx->hashObject, cbObjSize, NULL, 0, 0);
return newctx;
error:
if (newctx && !ctx)
free(newctx);
return NULL;
}
void ma_hash_free(MA_HASH_CTX *ctx)
{
if (ctx)
{
if (ctx->hHash)
BCryptDestroyHash(ctx->hHash);
if (ctx->hashObject)
free(ctx->hashObject);
if (ctx->free_me)
free(ctx);
}
}
void ma_hash_input(MA_HASH_CTX *ctx,
const unsigned char *buffer,
size_t len)
{
BCryptHashData(ctx->hHash, (PUCHAR)buffer, (LONG)len, 0);
}
void ma_hash_result(MA_HASH_CTX *ctx, unsigned char *digest)
{
BCryptFinishHash(ctx->hHash, digest, ctx->digest_len, 0);
}

137
vendor/MDBC/libmariadb/win32_errmsg.c vendored Normal file
View File

@ -0,0 +1,137 @@
/************************************************************************************
Copyright (C) 2019 MariaDB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Format Windows error, with optional text.
For "known" errors we also output their symbolic error constant, e.g
CERT_E_CN_NO_MATCH in addition to numeric value.
We also try to output English text for all error messages, as not to mess up
with encodings.
*/
void ma_format_win32_error(char* buf, size_t buflen, DWORD code, _Printf_format_string_ const char* fmt, ...)
{
char* cur = buf;
char* end = cur + buflen;
*cur = 0;
if (fmt)
{
va_list vargs;
va_start(vargs, fmt);
cur += vsnprintf_s(cur, end - cur, _TRUNCATE, fmt, vargs);
va_end(vargs);
}
if (code == 0)
return;
static struct map_entry
{
DWORD code;
const char* sym;
const char* msg;
}
map[] =
{
#define ENTRY(x, y) {x,#x, y}
ENTRY(SEC_E_WRONG_PRINCIPAL, "The target principal name is incorrect"),
ENTRY(CERT_E_CN_NO_MATCH,"The certificate's CN name does not match the passed value"),
ENTRY(SEC_E_UNTRUSTED_ROOT,"The certificate chain was issued by an authority that is not trusted"),
ENTRY(TRUST_E_CERT_SIGNATURE,"The signature of the certificate cannot be verified"),
ENTRY(SEC_E_CERT_EXPIRED,"The received certificate has expired"),
ENTRY(CERT_E_EXPIRED,"A required certificate is not within its validity period when verifying against the current system clock or the timestamp in the signed file"),
ENTRY(CRYPT_E_NO_REVOCATION_CHECK, "The revocation function was unable to check revocation for the certificate"),
ENTRY(CRYPT_E_REVOCATION_OFFLINE,"The revocation function was unable to check revocation because the revocation server was offline"),
ENTRY(CRYPT_E_REVOKED,"The certificate is revoked"),
ENTRY(SEC_E_CERT_UNKNOWN,"An unknown error occurred while processing the certificate"),
ENTRY(CERT_E_ROLE," A certificate that can only be used as an end-entity is being used as a CA or vice versa"),
ENTRY(CERT_E_WRONG_USAGE,"The certificate is not valid for the requested usage"),
ENTRY(SEC_E_ILLEGAL_MESSAGE, "The message received was unexpected or badly formatted"),
ENTRY(CERT_E_VALIDITYPERIODNESTING,"The validity periods of the certification chain do not nest correctly"),
ENTRY(CERT_E_PATHLENCONST,"A path length constraint in the certification chain has been violated"),
ENTRY(CERT_E_CRITICAL,"A certificate contains an unknown extension that is marked 'critical'"),
ENTRY(CERT_E_PURPOSE,"A certificate being used for a purpose other than the ones specified by its CA"),
ENTRY(CERT_E_ISSUERCHAINING,"A parent of a given certificate in fact did not issue that child certificate"),
ENTRY(CERT_E_MALFORMED, "A certificate is missing or has an empty value for an important field, such as a subject or issuer name"),
ENTRY(CERT_E_CHAINING,"A certificate chain could not be built to a trusted root authority"),
ENTRY(TRUST_E_FAIL," Generic trust failure"),
ENTRY(CERT_E_UNTRUSTEDTESTROOT,"The certification path terminates with the test root which is not trusted with the current policy settings"),
ENTRY(CERT_E_UNTRUSTEDROOT,"A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider"),
ENTRY(CERT_E_REVOCATION_FAILURE,"The revocation process could not continue - the certificate(s) could not be checked"),
ENTRY(SEC_E_ILLEGAL_MESSAGE, "The message received was unexpected or badly formatted"),
ENTRY(SEC_E_UNTRUSTED_ROOT, "Untrusted root certificate"),
ENTRY(SEC_E_BUFFER_TOO_SMALL, "Buffer too small"),
ENTRY(SEC_E_CRYPTO_SYSTEM_INVALID, "Cipher is not supported"),
ENTRY(SEC_E_INSUFFICIENT_MEMORY, "Out of memory"),
ENTRY(SEC_E_OUT_OF_SEQUENCE, "Invalid message sequence"),
ENTRY(SEC_E_DECRYPT_FAILURE, "The specified data could not be decrypted"),
ENTRY(SEC_I_INCOMPLETE_CREDENTIALS, "Incomplete credentials"),
ENTRY(SEC_E_ENCRYPT_FAILURE, "The specified data could not be encrypted"),
ENTRY(SEC_I_CONTEXT_EXPIRED, "The context has expired and can no longer be used"),
ENTRY(SEC_E_ALGORITHM_MISMATCH, "no cipher match"),
ENTRY(SEC_E_NO_CREDENTIALS, "no credentials"),
ENTRY(SEC_E_INVALID_TOKEN, "The token supplied to function is invalid"),
ENTRY(SEC_E_UNSUPPORTED_FUNCTION,"The function requested is not supported")
};
struct map_entry* entry = NULL;
if (cur > buf && cur[-1] != ' ' && cur[-1] != '.')
{
strncpy_s(cur,end-cur, ". ", _TRUNCATE);
cur += 2;
}
for (size_t i = 0; i < sizeof(map) / sizeof(map[0]); i++)
{
if (code == map[i].code)
{
entry = &map[i];
break;
}
}
if (cur > end - 20)
return;
if (entry)
{
sprintf_s(cur, end - cur, "%s. Error 0x%08lX(%s)", entry->msg, code, entry->sym);
}
else
{
cur += FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
cur, (DWORD)(end - cur), NULL);
while (cur > buf && (*cur == '\0' || *cur == '\n' || *cur == '\r' || *cur == '.'))
cur--;
if (*cur)
{
cur++;
*cur = 0;
}
sprintf_s(cur, end - cur, ". Error %lu/0x%08lX", code, code);
}
}

2
vendor/MDBC/libmariadb/win32_errmsg.h vendored Normal file
View File

@ -0,0 +1,2 @@
#include <windows.h>
void ma_format_win32_error(char* buf, size_t buflen, DWORD code, _Printf_format_string_ const char* fmt, ...);