Commit ea0a5cb0 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub Committed by Sergei Golubchik

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.
parent 99e5ae3b
......@@ -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)
......
......@@ -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
......
......@@ -30,6 +30,7 @@
#include <sddl.h>
struct IUnknown;
#include <shlwapi.h>
#include <winservice.h>
#include <string>
......@@ -916,7 +917,7 @@ static int create_db_instance(const char *datadir)
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);
......
......@@ -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>
......
......@@ -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;
......
......@@ -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
......@@ -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)
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment