diff options
author | Vladislav Vaintroub <wlad@mariadb.com> | 2021-11-19 14:03:51 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2021-12-15 19:13:57 +0100 |
commit | ea0a5cb0a4efbca1fc35885599e07baf10dc3e9e (patch) | |
tree | 8282d58bf98178b764b6f6f09c594670a4091e5a | |
parent | 99e5ae3b1a68ad1029f06aa3d2a5078d78cf19e5 (diff) | |
download | mariadb-git-ea0a5cb0a4efbca1fc35885599e07baf10dc3e9e.tar.gz |
MDEV-27092 Windows - services that have non-ASCII characters do not work with activeCodePage=UTF8
CreateServiceA, OpenServiceA, and couple of other functions do not work
correctly with non-ASCII character, in the special case where application
has defined activeCodePage=UTF8.
Workaround by redefining affected ANSI functions to own wrapper, which
works by converting narrow(ANSI) to wide, then calling wide function.
Deprecate original ANSI service functions, via declspec, so that we can catch
their use.
-rw-r--r-- | cmake/os/Windows.cmake | 4 | ||||
-rw-r--r-- | include/my_global.h | 8 | ||||
-rw-r--r-- | sql/mysql_install_db.cc | 3 | ||||
-rw-r--r-- | sql/mysqld.cc | 1 | ||||
-rw-r--r-- | sql/winmain.cc | 1 | ||||
-rw-r--r-- | sql/winservice.h | 177 | ||||
-rw-r--r-- | win/upgrade_wizard/CMakeLists.txt | 1 | ||||
-rw-r--r-- | win/upgrade_wizard/upgradeDlg.cpp | 18 |
8 files changed, 201 insertions, 12 deletions
diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index d9a0dfba46a..da75c73d585 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -60,8 +60,8 @@ ENDIF() ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE) ADD_DEFINITIONS(-D_WIN32_WINNT=0x0A00) -# We do not want the windows.h macros min/max -ADD_DEFINITIONS(-DNOMINMAX) +# We do not want the windows.h , or winsvc.h macros min/max +ADD_DEFINITIONS(-DNOMINMAX -DNOSERVICE) # Speed up build process excluding unused header files ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) diff --git a/include/my_global.h b/include/my_global.h index 224909116dd..ed213e69f85 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -29,6 +29,14 @@ #pragma GCC poison __WIN__ #endif +#if defined(_MSC_VER) +/* + Following functions have bugs, when used with UTF-8 active codepage. + #include <winservice.h> will use the non-buggy wrappers +*/ +#pragma deprecated("CreateServiceA", "OpenServiceA", "ChangeServiceConfigA") +#endif + /* InnoDB depends on some MySQL internals which other plugins should not need. This is because of InnoDB's foreign key support, "safe" binlog diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc index f712e29b843..026ac3e668e 100644 --- a/sql/mysql_install_db.cc +++ b/sql/mysql_install_db.cc @@ -30,6 +30,7 @@ #include <sddl.h> struct IUnknown; #include <shlwapi.h> +#include <winservice.h> #include <string> @@ -916,7 +917,7 @@ end: auto sc_manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (sc_manager) { - auto sc_handle= OpenServiceA(sc_manager,opt_service, DELETE); + auto sc_handle= OpenService(sc_manager,opt_service, DELETE); if (sc_handle) { DeleteService(sc_handle); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 808e590435a..46c28c862f6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -127,6 +127,7 @@ #ifdef _WIN32 #include <handle_connections_win.h> #include <sddl.h> +#include <winservice.h> /* SERVICE_STOPPED, SERVICE_RUNNING etc */ #endif #include <my_service_manager.h> diff --git a/sql/winmain.cc b/sql/winmain.cc index f999767cb27..bdad409065d 100644 --- a/sql/winmain.cc +++ b/sql/winmain.cc @@ -55,6 +55,7 @@ #include <windows.h> #include <string> #include <cassert> +#include <winservice.h> static SERVICE_STATUS svc_status{SERVICE_WIN32_OWN_PROCESS}; static SERVICE_STATUS_HANDLE svc_status_handle; diff --git a/sql/winservice.h b/sql/winservice.h index f9ab3eda332..a14ee73d146 100644 --- a/sql/winservice.h +++ b/sql/winservice.h @@ -17,11 +17,22 @@ /* Extract properties of a windows service binary path */ +#pragma once + #ifdef __cplusplus extern "C" { #endif -#include <windows.h> +#include <windows.h> +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4995) +#endif +#include <winsvc.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + typedef struct mysqld_service_properties_st { char mysqld_exe[MAX_PATH]; @@ -32,9 +43,171 @@ typedef struct mysqld_service_properties_st int version_patch; } mysqld_service_properties; -extern int get_mysql_service_properties(const wchar_t *bin_path, +extern int get_mysql_service_properties(const wchar_t *bin_path, mysqld_service_properties *props); + +#if !defined(UNICODE) +/* + The following wrappers workaround Windows bugs + with CreateService/OpenService with ANSI codepage UTF8. + + Apparently, these function in ANSI mode, for this codepage only + do *not* behave as expected (as-if string parameters were + converted to UTF16 and "wide" function were called) +*/ +#include <malloc.h> +static inline wchar_t* awstrdup(const char *str) +{ + if (!str) + return NULL; + size_t len= strlen(str) + 1; + wchar_t *wstr= (wchar_t *) malloc(sizeof(wchar_t)*len); + if (MultiByteToWideChar(GetACP(), 0, str, (int)len, wstr, (int)len) == 0) + { + free(wstr); + return NULL; + } + return wstr; +} + +#define AWSTRDUP(dest, src) \ + dest= awstrdup(src); \ + if (src && !dest) \ + { \ + ok= FALSE; \ + last_error = ERROR_OUTOFMEMORY; \ + goto end; \ + } + +static inline SC_HANDLE my_OpenService(SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAccess) +{ + wchar_t *w_ServiceName= NULL; + BOOL ok=TRUE; + DWORD last_error=0; + SC_HANDLE sch=NULL; + + AWSTRDUP(w_ServiceName, lpServiceName); + sch= OpenServiceW(hSCManager, w_ServiceName, dwDesiredAccess); + if (!sch) + { + ok= FALSE; + last_error= GetLastError(); + } + +end: + free(w_ServiceName); + if (!ok) + SetLastError(last_error); + return sch; +} + +static inline SC_HANDLE my_CreateService(SC_HANDLE hSCManager, + LPCSTR lpServiceName, LPCSTR lpDisplayName, + DWORD dwDesiredAccess, DWORD dwServiceType, + DWORD dwStartType, DWORD dwErrorControl, + LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, LPCSTR lpDependencies, + LPCSTR lpServiceStartName, LPCSTR lpPassword) +{ + wchar_t *w_ServiceName= NULL; + wchar_t *w_DisplayName= NULL; + wchar_t *w_BinaryPathName= NULL; + wchar_t *w_LoadOrderGroup= NULL; + wchar_t *w_Dependencies= NULL; + wchar_t *w_ServiceStartName= NULL; + wchar_t *w_Password= NULL; + SC_HANDLE sch = NULL; + DWORD last_error=0; + BOOL ok= TRUE; + + AWSTRDUP(w_ServiceName,lpServiceName); + AWSTRDUP(w_DisplayName,lpDisplayName); + AWSTRDUP(w_BinaryPathName, lpBinaryPathName); + AWSTRDUP(w_LoadOrderGroup, lpLoadOrderGroup); + AWSTRDUP(w_Dependencies, lpDependencies); + AWSTRDUP(w_ServiceStartName, lpServiceStartName); + AWSTRDUP(w_Password, lpPassword); + + sch= CreateServiceW( + hSCManager, w_ServiceName, w_DisplayName, dwDesiredAccess, dwServiceType, + dwStartType, dwErrorControl, w_BinaryPathName, w_LoadOrderGroup, + lpdwTagId, w_Dependencies, w_ServiceStartName, w_Password); + if(!sch) + { + ok= FALSE; + last_error= GetLastError(); + } + +end: + free(w_ServiceName); + free(w_DisplayName); + free(w_BinaryPathName); + free(w_LoadOrderGroup); + free(w_Dependencies); + free(w_ServiceStartName); + free(w_Password); + + if (!ok) + SetLastError(last_error); + return sch; +} + +static inline BOOL my_ChangeServiceConfig(SC_HANDLE hService, DWORD dwServiceType, + DWORD dwStartType, DWORD dwErrorControl, + LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, LPCSTR lpDependencies, + LPCSTR lpServiceStartName, LPCSTR lpPassword, + LPCSTR lpDisplayName) +{ + wchar_t *w_DisplayName= NULL; + wchar_t *w_BinaryPathName= NULL; + wchar_t *w_LoadOrderGroup= NULL; + wchar_t *w_Dependencies= NULL; + wchar_t *w_ServiceStartName= NULL; + wchar_t *w_Password= NULL; + SC_HANDLE sch = NULL; + DWORD last_error=0; + BOOL ok= TRUE; + + AWSTRDUP(w_DisplayName, lpDisplayName); + AWSTRDUP(w_BinaryPathName, lpBinaryPathName); + AWSTRDUP(w_LoadOrderGroup, lpLoadOrderGroup); + AWSTRDUP(w_Dependencies, lpDependencies); + AWSTRDUP(w_ServiceStartName, lpServiceStartName); + AWSTRDUP(w_Password, lpPassword); + + ok= ChangeServiceConfigW( + hService, dwServiceType, dwStartType, dwErrorControl, w_BinaryPathName, + w_LoadOrderGroup, lpdwTagId, w_Dependencies, w_ServiceStartName, + w_Password, w_DisplayName); + if (!ok) + { + last_error= GetLastError(); + } + +end: + free(w_DisplayName); + free(w_BinaryPathName); + free(w_LoadOrderGroup); + free(w_Dependencies); + free(w_ServiceStartName); + free(w_Password); + + if (last_error) + SetLastError(last_error); + return ok; +} +#undef AWSTRDUP + +#undef OpenService +#define OpenService my_OpenService +#undef ChangeServiceConfig +#define ChangeServiceConfig my_ChangeServiceConfig +#undef CreateService +#define CreateService my_CreateService +#endif + #ifdef __cplusplus } #endif diff --git a/win/upgrade_wizard/CMakeLists.txt b/win/upgrade_wizard/CMakeLists.txt index 20a06a41215..fd3560e1ee6 100644 --- a/win/upgrade_wizard/CMakeLists.txt +++ b/win/upgrade_wizard/CMakeLists.txt @@ -5,6 +5,7 @@ ENDIF() # We need MFC # /permissive- flag does not play well with MFC, disable it. STRING(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +REMOVE_DEFINITIONS(-DNOSERVICE) # fixes "already defined" warning in an AFX header FIND_PACKAGE(MFC) IF(NOT MFC_FOUND) diff --git a/win/upgrade_wizard/upgradeDlg.cpp b/win/upgrade_wizard/upgradeDlg.cpp index 80f7c18f757..7aae4890b51 100644 --- a/win/upgrade_wizard/upgradeDlg.cpp +++ b/win/upgrade_wizard/upgradeDlg.cpp @@ -141,24 +141,24 @@ void CUpgradeDlg::PopulateServicesList() ErrorExit("OpenSCManager failed"); } - static BYTE buf[64*1024]; + static BYTE buf[2*64*1024]; static BYTE configBuffer[8*1024]; DWORD bufsize= sizeof(buf); DWORD bufneed; DWORD num_services; - BOOL ok= EnumServicesStatusEx(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, + BOOL ok= EnumServicesStatusExW(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, buf, bufsize, &bufneed, &num_services, NULL, NULL); if(!ok) ErrorExit("EnumServicesStatusEx failed"); - LPENUM_SERVICE_STATUS_PROCESS info = - (LPENUM_SERVICE_STATUS_PROCESS)buf; + LPENUM_SERVICE_STATUS_PROCESSW info = + (LPENUM_SERVICE_STATUS_PROCESSW)buf; int index=-1; for (ULONG i=0; i < num_services; i++) { - SC_HANDLE service= OpenService(scm, info[i].lpServiceName, + SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName, SERVICE_QUERY_CONFIG); if (!service) continue; @@ -187,7 +187,11 @@ void CUpgradeDlg::PopulateServicesList() ServiceProperties props; props.myini= service_props.inifile; props.datadir= service_props.datadir; - props.servicename = info[i].lpServiceName; + char service_name_buf[1024]; + WideCharToMultiByte(GetACP(), 0, info[i].lpServiceName, -1, + service_name_buf, sizeof(service_name_buf), + 0, 0); + props.servicename= service_name_buf; if (service_props.version_major) { char ver[64]; @@ -198,7 +202,7 @@ void CUpgradeDlg::PopulateServicesList() else props.version= "<unknown>"; - index = m_Services.AddString(info[i].lpServiceName); + index = m_Services.AddString(service_name_buf); services.resize(index+1); services[index] = props; } |