The Rutoken driver installer tries to start this service, and fails if it doesn't exist.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54396
-- v2: scardsvr: Add stub service. wine.inf: Always use FLG_ADDREG_APPEND for SvcHost entries. setupapi: Create the registry value if it doesn't exist in append_multi_sz_value(). setupapi: Fail installation when trying to append to a registry value of the wrong type. setupapi/tests: Add tests for FLG_ADDREG_APPEND.
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/setupapi/tests/install.c | 100 ++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+)
diff --git a/dlls/setupapi/tests/install.c b/dlls/setupapi/tests/install.c index 2bbcbec88dc..0334450dfce 100644 --- a/dlls/setupapi/tests/install.c +++ b/dlls/setupapi/tests/install.c @@ -2297,6 +2297,105 @@ static void test_rename(void) ok(ret, "Failed to delete directory, error %lu.\n", GetLastError()); }
+static void test_append_reg(void) +{ + static const char inf_data[] = "[Version]\n" + "Signature="$Chicago$"\n" + "[DefaultInstall]\n" + "AddReg=reg_section\n" + "[reg_section]\n" + "HKCU,Software\winetest_setupapi,value,0x10008,"data"\n"; + + void *context = SetupInitDefaultQueueCallbackEx(NULL, INVALID_HANDLE_VALUE, 0, 0, 0); + char path[MAX_PATH]; + DWORD type, size; + char value[20]; + HINF hinf; + BOOL ret; + HKEY key; + LONG l; + + create_inf_file("test.inf", inf_data); + sprintf(path, "%s\test.inf", CURR_DIR); + hinf = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "Failed to open INF file, error %#lx.\n", GetLastError()); + + /* Key doesn't exist yet. */ + + RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_setupapi"); + + ret = SetupInstallFromInfSectionA(NULL, hinf, "DefaultInstall", SPINST_REGISTRY, + NULL, "C:\", 0, SetupDefaultQueueCallbackA, context, NULL, NULL); + ok(ret, "Failed to install, error %#lx.\n", GetLastError()); + + l = RegOpenKeyA(HKEY_CURRENT_USER, "Software\winetest_setupapi", &key); + ok(!l, "Got error %lu.\n", l); + size = sizeof(value); + l = RegQueryValueExA(key, "value", NULL, &type, (BYTE *)value, &size); + todo_wine ok(!l, "Got error %lu.\n", l); + if (!l) + { + ok(type == REG_MULTI_SZ, "Got type %#lx.\n", type); + ok(size == sizeof("data\0"), "Got size %lu.\n", size); + ok(!memcmp(value, "data\0", size), "Got data %s.\n", debugstr_an(value, size)); + } + + /* Key exists and already has a value. */ + + l = RegSetValueExA(key, "value", 0, REG_MULTI_SZ, (const BYTE *)"foo\0bar\0", sizeof("foo\0bar\0")); + ok(!l, "Got error %lu.\n", l); + + ret = SetupInstallFromInfSectionA(NULL, hinf, "DefaultInstall", SPINST_REGISTRY, + NULL, "C:\", 0, SetupDefaultQueueCallbackA, context, NULL, NULL); + ok(ret, "Failed to install, error %#lx.\n", GetLastError()); + + size = sizeof(value); + l = RegQueryValueExA(key, "value", NULL, &type, (BYTE *)value, &size); + ok(!l, "Got error %lu.\n", l); + ok(type == REG_MULTI_SZ, "Got type %#lx.\n", type); + ok(size == sizeof("foo\0bar\0data\0"), "Got size %lu.\n", size); + ok(!memcmp(value, "foo\0bar\0data\0", size), "Got data %s.\n", debugstr_an(value, size)); + + /* Key exists and already has the value to be added. */ + + ret = SetupInstallFromInfSectionA(NULL, hinf, "DefaultInstall", SPINST_REGISTRY, + NULL, "C:\", 0, SetupDefaultQueueCallbackA, context, NULL, NULL); + ok(ret, "Failed to install, error %#lx.\n", GetLastError()); + + size = sizeof(value); + l = RegQueryValueExA(key, "value", NULL, &type, (BYTE *)value, &size); + ok(!l, "Got error %lu.\n", l); + ok(type == REG_MULTI_SZ, "Got type %#lx.\n", type); + ok(size == sizeof("foo\0bar\0data\0"), "Got size %lu.\n", size); + ok(!memcmp(value, "foo\0bar\0data\0", size), "Got data %s.\n", debugstr_an(value, size)); + + /* Key exists and already has a value of the wrong type. */ + + l = RegSetValueExA(key, "value", 0, REG_SZ, (const BYTE *)"string", sizeof("string")); + ok(!l, "Got error %lu.\n", l); + + ret = SetupInstallFromInfSectionA(NULL, hinf, "DefaultInstall", SPINST_REGISTRY, + NULL, "C:\", 0, SetupDefaultQueueCallbackA, context, NULL, NULL); + todo_wine ok(!ret, "Expected failure.\n"); + todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got error %#lx.\n", GetLastError()); + + size = sizeof(value); + l = RegQueryValueExA(key, "value", NULL, &type, (BYTE *)value, &size); + ok(!l, "Got error %lu.\n", l); + ok(type == REG_SZ, "Got type %#lx.\n", type); + ok(size == sizeof("string"), "Got size %lu.\n", size); + ok(!memcmp(value, "string", size), "Got data %s.\n", debugstr_an(value, size)); + + RegCloseKey(key); + + l = RegDeleteKeyA(HKEY_CURRENT_USER, "Software\winetest_setupapi"); + ok(!l, "Got error %lu.\n", l); + + SetupCloseInfFile(hinf); + ret = DeleteFileA("test.inf"); + ok(ret, "Failed to delete INF file, error %lu.\n", GetLastError()); +} + static WCHAR service_name[] = L"Wine Test Service"; static SERVICE_STATUS_HANDLE service_handle; static HANDLE stop_event; @@ -2406,6 +2505,7 @@ START_TEST(install) test_start_copy(); test_register_dlls(); test_rename(); + test_append_reg();
UnhookWindowsHookEx(hhook);
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/setupapi/install.c | 29 ++++++++++++++++++++++------- dlls/setupapi/tests/install.c | 4 ++-- 2 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/dlls/setupapi/install.c b/dlls/setupapi/install.c index 532ac6c36a6..435918e815e 100644 --- a/dlls/setupapi/install.c +++ b/dlls/setupapi/install.c @@ -19,6 +19,7 @@ */
#include <stdarg.h> +#include <stdbool.h>
#define COBJMACROS
@@ -227,17 +228,26 @@ static HKEY get_root_key( const WCHAR *name, HKEY def_root ) * * Append a multisz string to a multisz registry value. */ -static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings, +static bool append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings, DWORD str_size ) { DWORD size, type, total; WCHAR *buffer, *p;
- if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; - if (type != REG_MULTI_SZ) return; + if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return true; + if (type != REG_MULTI_SZ) + { + WARN( "value %s exists but has wrong type %#lx\n", debugstr_w(value), type ); + SetLastError( ERROR_INVALID_DATA ); + return false; + }
- if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return; - if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return false; + if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) + { + HeapFree( GetProcessHeap(), 0, buffer ); + return false; + }
/* compare each string against all the existing ones */ total = size; @@ -261,8 +271,9 @@ static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *s TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) ); RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total ); } - done: + HeapFree( GetProcessHeap(), 0, buffer ); + return true; }
@@ -374,7 +385,11 @@ static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context if (flags & FLG_ADDREG_APPEND) { if (!str) return TRUE; - append_multi_sz_value( hkey, value, str, size ); + if (!append_multi_sz_value( hkey, value, str, size )) + { + HeapFree( GetProcessHeap(), 0, str ); + return FALSE; + } HeapFree( GetProcessHeap(), 0, str ); return TRUE; } diff --git a/dlls/setupapi/tests/install.c b/dlls/setupapi/tests/install.c index 0334450dfce..10c93482ece 100644 --- a/dlls/setupapi/tests/install.c +++ b/dlls/setupapi/tests/install.c @@ -2376,8 +2376,8 @@ static void test_append_reg(void)
ret = SetupInstallFromInfSectionA(NULL, hinf, "DefaultInstall", SPINST_REGISTRY, NULL, "C:\", 0, SetupDefaultQueueCallbackA, context, NULL, NULL); - todo_wine ok(!ret, "Expected failure.\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "Got error %#lx.\n", GetLastError()); + ok(!ret, "Expected failure.\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "Got error %#lx.\n", GetLastError());
size = sizeof(value); l = RegQueryValueExA(key, "value", NULL, &type, (BYTE *)value, &size);
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/setupapi/install.c | 21 ++++++++++++++++++++- dlls/setupapi/tests/install.c | 11 ++++------- 2 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/dlls/setupapi/install.c b/dlls/setupapi/install.c index 435918e815e..8a28bfcc4e1 100644 --- a/dlls/setupapi/install.c +++ b/dlls/setupapi/install.c @@ -233,8 +233,27 @@ static bool append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *s { DWORD size, type, total; WCHAR *buffer, *p; + LONG ret; + + if ((ret = RegQueryValueExW( hkey, value, NULL, &type, NULL, &size ))) + { + if (ret != ERROR_FILE_NOT_FOUND) + { + ERR( "failed to query value %s, error %lu\n", debugstr_w(value), ret ); + SetLastError( ret ); + return false; + } + + if ((ret = RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)strings, str_size * sizeof(WCHAR) ))) + { + ERR( "failed to set value %s, error %lu\n", debugstr_w(value), ret ); + SetLastError( ret ); + return false; + } + + return true; + }
- if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return true; if (type != REG_MULTI_SZ) { WARN( "value %s exists but has wrong type %#lx\n", debugstr_w(value), type ); diff --git a/dlls/setupapi/tests/install.c b/dlls/setupapi/tests/install.c index 10c93482ece..318f1294210 100644 --- a/dlls/setupapi/tests/install.c +++ b/dlls/setupapi/tests/install.c @@ -2332,13 +2332,10 @@ static void test_append_reg(void) ok(!l, "Got error %lu.\n", l); size = sizeof(value); l = RegQueryValueExA(key, "value", NULL, &type, (BYTE *)value, &size); - todo_wine ok(!l, "Got error %lu.\n", l); - if (!l) - { - ok(type == REG_MULTI_SZ, "Got type %#lx.\n", type); - ok(size == sizeof("data\0"), "Got size %lu.\n", size); - ok(!memcmp(value, "data\0", size), "Got data %s.\n", debugstr_an(value, size)); - } + ok(!l, "Got error %lu.\n", l); + ok(type == REG_MULTI_SZ, "Got type %#lx.\n", type); + ok(size == sizeof("data\0"), "Got size %lu.\n", size); + ok(!memcmp(value, "data\0", size), "Got data %s.\n", debugstr_an(value, size));
/* Key exists and already has a value. */
From: Zebediah Figura zfigura@codeweavers.com
Now that FLG_ADDREG_APPEND is changed to correctly create the value if it doesn't exist, this is safe, and less error-prone when adding new services. --- loader/wine.inf.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 3c9cb9bc6dc..58013064753 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2370,15 +2370,15 @@ ErrorControl=1
[BITSServiceKeys] HKR,Parameters,"ServiceDll",,"%11%\qmgr.dll" -HKLM,%CurrentVersionNT%\SvcHost,"netsvcs",0x00010000,"BITS" +HKLM,%CurrentVersionNT%\SvcHost,"netsvcs",0x00010008,"BITS"
[EventLogServiceKeys] HKR,Parameters,"ServiceDll",,"%11%\wevtsvc.dll" -HKLM,%CurrentVersionNT%\SvcHost,"LocalServiceNetworkRestricted",0x00010000,"EventLog" +HKLM,%CurrentVersionNT%\SvcHost,"LocalServiceNetworkRestricted",0x00010008,"EventLog"
[StiServiceKeys] HKR,Parameters,"ServiceDll",,"%11%\wiaservc.dll" -HKLM,%CurrentVersionNT%\SvcHost,"imgsvc",0x00010000,"StiSvc" +HKLM,%CurrentVersionNT%\SvcHost,"imgsvc",0x00010008,"StiSvc"
[PlugPlayService] Description="Enables automatic configuration of devices"
From: Zebediah Figura zfigura@codeweavers.com
The Rutoken driver installer tries to start this service, and fails if it doesn't exist.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54396 --- configure.ac | 1 + dlls/scardsvr/Makefile.in | 5 +++ dlls/scardsvr/scardsvr.c | 88 +++++++++++++++++++++++++++++++++++++ dlls/scardsvr/scardsvr.spec | 3 ++ loader/wine.inf.in | 17 +++++++ 5 files changed, 114 insertions(+) create mode 100644 dlls/scardsvr/Makefile.in create mode 100644 dlls/scardsvr/scardsvr.c create mode 100644 dlls/scardsvr/scardsvr.spec
diff --git a/configure.ac b/configure.ac index 9ff7c5e8914..2291449c4d0 100644 --- a/configure.ac +++ b/configure.ac @@ -2960,6 +2960,7 @@ WINE_CONFIG_MAKEFILE(dlls/sapi) WINE_CONFIG_MAKEFILE(dlls/sapi/tests) WINE_CONFIG_MAKEFILE(dlls/sas) WINE_CONFIG_MAKEFILE(dlls/scarddlg) +WINE_CONFIG_MAKEFILE(dlls/scardsvr) WINE_CONFIG_MAKEFILE(dlls/sccbase) WINE_CONFIG_MAKEFILE(dlls/schannel) WINE_CONFIG_MAKEFILE(dlls/schannel/tests) diff --git a/dlls/scardsvr/Makefile.in b/dlls/scardsvr/Makefile.in new file mode 100644 index 00000000000..c89e86c17d8 --- /dev/null +++ b/dlls/scardsvr/Makefile.in @@ -0,0 +1,5 @@ +MODULE = scardsvr.dll +IMPORTS = advapi32 + +C_SRCS = \ + scardsvr.c diff --git a/dlls/scardsvr/scardsvr.c b/dlls/scardsvr/scardsvr.c new file mode 100644 index 00000000000..5c4e26f5362 --- /dev/null +++ b/dlls/scardsvr/scardsvr.c @@ -0,0 +1,88 @@ +/* + * Smart card service + * + * Copyright 2014 Nikolay Sivov for CodeWeavers + * + * This library 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 Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winsvc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winscard); + +static SERVICE_STATUS_HANDLE service_handle; +static HANDLE stop_event; + +static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context) +{ + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + switch(ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + TRACE("Shutting down.\n"); + status.dwCurrentState = SERVICE_STOP_PENDING; + status.dwControlsAccepted = 0; + SetServiceStatus(service_handle, &status); + SetEvent(stop_event); + return ERROR_SUCCESS; + + default: + FIXME("Got unknown control %#lx.\n", ctrl); + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(service_handle, &status); + return ERROR_SUCCESS; + } +} + +void WINAPI CalaisMain(DWORD argc, WCHAR **argv) +{ + SERVICE_STATUS status; + + TRACE("Starting service.\n"); + + stop_event = CreateEventW(NULL, TRUE, FALSE, NULL); + + if (!(service_handle = RegisterServiceCtrlHandlerExW(L"scardsvr", service_handler, NULL))) + return; + + status.dwServiceType = SERVICE_WIN32; + status.dwCurrentState = SERVICE_RUNNING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 10000; + SetServiceStatus(service_handle, &status); + + WaitForSingleObject(stop_event, INFINITE); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = 0; + SetServiceStatus(service_handle, &status); + TRACE("Service stopped.\n"); +} diff --git a/dlls/scardsvr/scardsvr.spec b/dlls/scardsvr/scardsvr.spec new file mode 100644 index 00000000000..c33a1aa6569 --- /dev/null +++ b/dlls/scardsvr/scardsvr.spec @@ -0,0 +1,3 @@ +@ stdcall -private CalaisMain(long ptr) +@ stub InitSmartCardService +# @ stub SvchostPushServiceGlobals diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 58013064753..a306b07dc26 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -171,6 +171,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService AddService=TermService,0,TerminalServices @@ -190,6 +191,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService AddService=TermService,0,TerminalServices @@ -209,6 +211,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService AddService=TermService,0,TerminalServices @@ -228,6 +231,7 @@ AddService=EventLog,0x800,EventLogService AddService=HTTP,0,HTTPService AddService=MSIServer,0,MSIService AddService=RpcSs,0,RpcSsService +AddService=scardsvr,0,ScardSvrService AddService=Spooler,0,SpoolerService AddService=StiSvc,0,StiService AddService=TermService,0,TerminalServices @@ -2321,6 +2325,19 @@ ServiceType=32 StartType=3 ErrorControl=1
+[ScardSvrService] +AddReg=ScardSvrServiceKeys +DisplayName="Smart card server" +ServiceBinary="%11%\svchost.exe -k netsvcs" +ServiceType=32 +StartType=3 +ErrorControl=1 + +[ScardSvrServiceKeys] +HKR,Parameters,"ServiceDll",,"%11%\scardsvr.dll" +HKR,Parameters,"ServiceMain",,"CalaisMain" +HKLM,%CurrentVersionNT%\SvcHost,"netsvcs",0x00010008,"scardsvr" + [SpoolerService] AddReg=SpoolerServiceKeys Description="Loads files to memory for later printing"
v2: v2: fix svchost key handling, add display name, comment out SvchostPushServiceGlobals in case svchost.exe ever grows support for that
The CI is hitting unrelated intermittent failures in mmdevapi.