[PATCH 0/3] MR10150: advapi32/tests: Add some tests for LockServiceDatabase().
From: Dmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru> --- dlls/advapi32/tests/service.c | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c index fe25013bfab..6bfcec81297 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -3023,6 +3023,62 @@ static void test_EventLog(void) CloseServiceHandle(scm_handle); } +static void test_LockServiceDatabase(void) +{ + static const struct + { + DWORD access, error; + } td[] = + { + { 0, ERROR_ACCESS_DENIED }, + { SC_MANAGER_CONNECT, ERROR_ACCESS_DENIED }, + { SC_MANAGER_LOCK, 0 } + }; + SC_HANDLE hscm; + SC_LOCK lock; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(td); i++) + { + winetest_push_context("%d", i); + + hscm = OpenSCManagerW(NULL, NULL, td[i].access); + if (!hscm) + { + skip("OpenSCManager(%08lx) error %lu, skipping the tests\n", td[i].access, GetLastError()); + break; + } + + SetLastError(0xdeadbeef); + lock = LockServiceDatabase(hscm); + if (!td[i].error) + { + ok(lock != NULL, "LockServiceDatabase() error %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = UnlockServiceDatabase(lock); + ok(ret, "UnlockServiceDatabase() error %lu\n", GetLastError()); + } + else + { + todo_wine + ok(!lock, "LockServiceDatabase() should fail\n"); + todo_wine + ok(td[i].error == GetLastError(), "got %lu\n", GetLastError()); + } + + SetLastError(0xdeadbeef); + ret = UnlockServiceDatabase(lock); + todo_wine + ok(!ret, "UnlockServiceDatabase() should fail\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_SERVICE_LOCK, "got %lu\n", GetLastError()); + + winetest_pop_context(); + } + + CloseServiceHandle(hscm); +} + static DWORD WINAPI ctrl_handler(DWORD ctl, DWORD type, void *data, void *user) { HANDLE evt = user; @@ -3110,6 +3166,7 @@ START_TEST(service) test_get_displayname(); test_get_servicekeyname(); test_query_svc(); + test_LockServiceDatabase(); /* Services may start or stop between enumeration calls, leading to * inconsistencies and failures. So we may need a couple attempts. -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10150
From: Dmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru> --- programs/services/rpc.c | 57 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 6fef374402d..99a25ed4a5a 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -59,6 +59,7 @@ typedef enum SC_HTYPE_DONT_CARE = 0, SC_HTYPE_MANAGER, SC_HTYPE_SERVICE, + SC_HTYPE_LOCK, SC_HTYPE_NOTIFY } SC_HANDLE_TYPE; @@ -92,6 +93,11 @@ struct sc_service_handle /* service handle */ struct sc_notify_handle *notify; }; +struct sc_lock_handle +{ + struct sc_handle hdr; +}; + static void sc_notify_retain(struct sc_notify_handle *notify) { InterlockedIncrement(¬ify->ref); @@ -265,6 +271,17 @@ static DWORD validate_notify_handle(SC_RPC_HANDLE handle, DWORD needed_access, s return err; } +static DWORD validate_lock_handle(SC_RPC_HANDLE handle, struct sc_lock_handle **lock) +{ + struct sc_handle *hdr = handle; + + if (hdr->type != SC_HTYPE_LOCK) + return ERROR_INVALID_SERVICE_LOCK; + + *lock = (struct sc_lock_handle *)hdr; + return ERROR_SUCCESS; +} + DWORD __cdecl svcctl_OpenSCManagerW( MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */ LPCWSTR DatabaseName, @@ -324,6 +341,12 @@ static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle) free(service); break; } + case SC_HTYPE_LOCK: + { + struct sc_lock_handle *lock = (struct sc_lock_handle *)hdr; + free(lock); + break; + } default: WINE_ERR("invalid handle type %d\n", hdr->type); RpcRaiseException(ERROR_INVALID_HANDLE); @@ -1408,19 +1431,41 @@ void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock) { } -DWORD __cdecl svcctl_LockServiceDatabase(SC_RPC_HANDLE manager, SC_RPC_LOCK *lock) +DWORD __cdecl svcctl_LockServiceDatabase(SC_RPC_HANDLE hmngr, SC_RPC_LOCK *handle) { - TRACE("(%p, %p)\n", manager, lock); + DWORD err; + struct sc_manager_handle *manager; + struct sc_lock_handle *lock; + + TRACE("(%p, %p)\n", hmngr, handle); + + if ((err = validate_scm_handle(hmngr, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS) + return err; + + if (!(lock = malloc(sizeof(*lock)))) + return ERROR_NOT_ENOUGH_SERVER_MEMORY; + + lock->hdr.type = SC_HTYPE_LOCK; + lock->hdr.access = 0; + + *handle = &lock->hdr; - *lock = (SC_RPC_LOCK)0xdeadbeef; return ERROR_SUCCESS; } -DWORD __cdecl svcctl_UnlockServiceDatabase(SC_RPC_LOCK *lock) +DWORD __cdecl svcctl_UnlockServiceDatabase(SC_RPC_LOCK *handle) { - TRACE("(&%p)\n", *lock); + DWORD err; + struct sc_lock_handle *lock; + + TRACE("(&%p)\n", *handle); + + if ((err = validate_lock_handle(*handle, &lock)) != ERROR_SUCCESS) + return err; + + SC_RPC_HANDLE_destroy(*handle); + *handle = NULL; - *lock = NULL; return ERROR_SUCCESS; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10150
From: Dmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru> --- dlls/advapi32/Makefile.in | 1 + dlls/advapi32/service.c | 173 +++++++++++++++++++++++++++++++++- dlls/advapi32/svcctl.idl | 3 + dlls/advapi32/tests/service.c | 4 - 4 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 dlls/advapi32/svcctl.idl diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in index d1f9e9996cc..53abe476bde 100644 --- a/dlls/advapi32/Makefile.in +++ b/dlls/advapi32/Makefile.in @@ -15,4 +15,5 @@ SOURCES = \ registry.c \ security.c \ service.c \ + svcctl.idl \ wmi.c diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index e6b243a46f4..bcf92d7f5d4 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -24,20 +24,65 @@ #include "windef.h" #include "winbase.h" #include "winsvc.h" +#include "svcctl.h" #include "wine/debug.h" +#include "wine/exception.h" #include "advapi32_misc.h" WINE_DEFAULT_DEBUG_CHANNEL(service); +static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr ) +{ + return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode ); +} + +static DWORD map_exception_code( DWORD exception_code ) +{ + switch (exception_code) + { + case RPC_X_NULL_REF_POINTER: + return ERROR_INVALID_ADDRESS; + case RPC_X_ENUM_VALUE_OUT_OF_RANGE: + case RPC_X_BYTE_COUNT_TOO_SMALL: + return ERROR_INVALID_PARAMETER; + case RPC_S_INVALID_BINDING: + case RPC_X_SS_IN_NULL_CONTEXT: + return ERROR_INVALID_HANDLE; + default: + return exception_code; + } +} + /****************************************************************************** * LockServiceDatabase [ADVAPI32.@] */ SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager ) { - /* this function is a no-op in Vista and above */ + SC_LOCK handle = NULL; + DWORD err; + TRACE("%p\n", manager); - return (SC_LOCK)0xdeadbeef; + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } + + __TRY + { + err = svcctl_LockServiceDatabase( manager, &handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!err) return handle; + SetLastError( err ); + return 0; } /****************************************************************************** @@ -45,9 +90,35 @@ SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager ) */ BOOL WINAPI UnlockServiceDatabase( SC_LOCK lock ) { - /* this function is a no-op in Vista and above */ + DWORD err; + TRACE("%p\n", lock); - return TRUE; + + if (!lock) + { + SetLastError( ERROR_INVALID_SERVICE_LOCK ); + return FALSE; + } + + __TRY + { + err = svcctl_UnlockServiceDatabase( &lock ); + } + __EXCEPT(rpc_filter) + { + err = GetExceptionCode(); + + if (err == ERROR_INVALID_HANDLE) + err = ERROR_INVALID_SERVICE_LOCK; + else + err = map_exception_code( err ); + } + __ENDTRY + + if (!err) return TRUE; + SetLastError( err ); + return FALSE; + } /****************************************************************************** @@ -423,3 +494,97 @@ BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState, *lpServicesReturned = 0; return TRUE; } + +static handle_t rpc_wstr_bind( RPC_WSTR str ) +{ + WCHAR transport[] = SVCCTL_TRANSPORT; + WCHAR endpoint[] = SVCCTL_ENDPOINT; + RPC_WSTR binding_str; + RPC_STATUS status; + handle_t rpc_handle; + + status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str ); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingComposeW failed, error %ld\n", status); + return NULL; + } + + status = RpcBindingFromStringBindingW( binding_str, &rpc_handle ); + RpcStringFreeW( &binding_str ); + + if (status != RPC_S_OK) + { + ERR("Couldn't connect to services.exe, error %ld\n", status); + return NULL; + } + + return rpc_handle; +} + +static handle_t rpc_cstr_bind(RPC_CSTR str) +{ + RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA; + RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA; + RPC_CSTR binding_str; + RPC_STATUS status; + handle_t rpc_handle; + + status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str ); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingComposeA failed, error %ld\n", status); + return NULL; + } + + status = RpcBindingFromStringBindingA( binding_str, &rpc_handle ); + RpcStringFreeA( &binding_str ); + + if (status != RPC_S_OK) + { + ERR("Couldn't connect to services.exe, error %ld\n", status); + return NULL; + } + + return rpc_handle; +} + +handle_t __RPC_USER MACHINE_HANDLEA_bind( MACHINE_HANDLEA name ) +{ + return rpc_cstr_bind( (RPC_CSTR)name ); +} + +void __RPC_USER MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +handle_t __RPC_USER MACHINE_HANDLEW_bind( MACHINE_HANDLEW name ) +{ + return rpc_wstr_bind( (RPC_WSTR)name ); +} + +void __RPC_USER MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +handle_t __RPC_USER SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name ) +{ + return rpc_wstr_bind( (RPC_WSTR)name ); +} + +void __RPC_USER SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len ) +{ + return malloc(len); +} + +void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr ) +{ + free(ptr); +} diff --git a/dlls/advapi32/svcctl.idl b/dlls/advapi32/svcctl.idl new file mode 100644 index 00000000000..b1bc8545d78 --- /dev/null +++ b/dlls/advapi32/svcctl.idl @@ -0,0 +1,3 @@ +#pragma makedep client + +#include "wine/svcctl.idl" diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c index 6bfcec81297..33ff25d6f19 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -3060,17 +3060,13 @@ static void test_LockServiceDatabase(void) } else { - todo_wine ok(!lock, "LockServiceDatabase() should fail\n"); - todo_wine ok(td[i].error == GetLastError(), "got %lu\n", GetLastError()); } SetLastError(0xdeadbeef); ret = UnlockServiceDatabase(lock); - todo_wine ok(!ret, "UnlockServiceDatabase() should fail\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_SERVICE_LOCK, "got %lu\n", GetLastError()); winetest_pop_context(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10150
participants (2)
-
Dmitry Timoshkov -
Dmitry Timoshkov (@dmitry)