From a55cc1a45e8eb67d5f3e94c496939fe682c7733b Mon Sep 17 00:00:00 2001 From: Mikolaj Zalewski Date: Tue, 25 Sep 2007 16:21:49 -0700 Subject: [PATCH] services.exe/advapi32: move ChangeServiceConfigW to services.exe --- dlls/advapi32/service.c | 74 +++++++++++----------------- dlls/advapi32/tests/service.c | 20 ++++++++ include/wine/svcctl.idl | 20 +++++++- programs/services/rpc.c | 107 +++++++++++++++++++++++++++++++++++++++++ programs/services/services.c | 2 - programs/services/services.h | 1 6 files changed, 176 insertions(+), 48 deletions(-) diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index a7ad8dc..65e5104 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -249,6 +249,18 @@ static inline LPWSTR SERV_dupmulti(LPCST return wstr; } +static inline DWORD multisz_cb(LPCWSTR wmultisz) +{ + const WCHAR *wptr = wmultisz; + + if (wmultisz == NULL) + return 0; + + while (*wptr) + wptr += lstrlenW(wptr)+1; + return (wptr - wmultisz + 1)*sizeof(WCHAR); +} + /****************************************************************************** * RPC connection with servies.exe */ @@ -1394,7 +1406,7 @@ CreateServiceW( SC_HANDLE hSCManager, LP struct sc_service *hsvc = NULL; DWORD new_mask = dwDesiredAccess; DWORD len, err; - SIZE_T depslen = 0, passwdlen; + SIZE_T passwdlen; TRACE("%p %s %s\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName)); @@ -1412,16 +1424,6 @@ CreateServiceW( SC_HANDLE hSCManager, LP return NULL; } - if (lpDependencies) - { - const WCHAR *wptr = lpDependencies; - while (*wptr) - wptr += strlenW(wptr)+1; - depslen = (wptr - lpDependencies + 1)*sizeof(WCHAR); - } - else - depslen = 0; - if (lpPassword) passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR); else @@ -1443,8 +1445,9 @@ CreateServiceW( SC_HANDLE hSCManager, LP err = svcctl_CreateServiceW(hscm->hdr.rpc_handle, &hscm->hdr.server_handle, lpServiceName, lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, - lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies, depslen, - lpServiceStartName, (LPBYTE)lpPassword, passwdlen, &hsvc->hdr.server_handle); + lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies, + multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen, + &hsvc->hdr.server_handle); if (err != ERROR_SUCCESS) { @@ -2257,55 +2260,34 @@ BOOL WINAPI ChangeServiceConfigW( SC_HAN LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies, LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName) { - struct reg_value val[10]; struct sc_service *hsvc; - DWORD r = ERROR_SUCCESS; - HKEY hKey; - int n = 0; + DWORD cb_pwd; + DWORD err; TRACE("%p %d %d %d %s %s %p %p %s %s %s\n", hService, dwServiceType, dwStartType, dwErrorControl, debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName), debugstr_w(lpPassword), debugstr_w(lpDisplayName) ); - + hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE); if (!hsvc) { SetLastError( ERROR_INVALID_HANDLE ); return FALSE; } - hKey = hsvc->hkey; - - if( dwServiceType != SERVICE_NO_CHANGE ) - service_set_dword( &val[n++], szType, &dwServiceType ); - - if( dwStartType != SERVICE_NO_CHANGE ) - service_set_dword( &val[n++], szStart, &dwStartType ); - - if( dwErrorControl != SERVICE_NO_CHANGE ) - service_set_dword( &val[n++], szError, &dwErrorControl ); - - if( lpBinaryPathName ) - service_set_string( &val[n++], szImagePath, lpBinaryPathName ); - if( lpLoadOrderGroup ) - service_set_string( &val[n++], szGroup, lpLoadOrderGroup ); + cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0; - /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup - * There is no such key as what szDependencies refers to */ - if( lpDependencies ) - service_set_multi_string( &val[n++], szDependencies, lpDependencies ); + err = svcctl_ChangeServiceConfigW(hsvc->hdr.rpc_handle, &hsvc->hdr.server_handle, dwServiceType, + dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, + (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName, + (const BYTE *)lpPassword, cb_pwd, lpDisplayName); - if( lpPassword ) - FIXME("ignoring password\n"); - - if( lpServiceStartName ) - service_set_string( &val[n++], szObjectName, lpServiceStartName ); - - r = service_write_values( hsvc->hkey, val, n ); - - return (r == ERROR_SUCCESS) ? TRUE : FALSE ; + if (err != ERROR_SUCCESS) + SetLastError(err); + + return err == ERROR_SUCCESS; } /****************************************************************************** diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c index 34c0ea7..e02e489 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -723,6 +723,7 @@ static void test_sequence(void) DWORD given, needed; static const CHAR servicename [] = "Winetest"; static const CHAR displayname [] = "Winetest dummy service"; + static const CHAR displayname2[] = "Winetest dummy service (2)"; static const CHAR pathname [] = "we_dont_care.exe"; static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0\0"; static const CHAR password [] = ""; @@ -816,6 +817,25 @@ static void test_sequence(void) ok(!strcmp(config->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName); ok(!strcmp(config->lpDisplayName, displayname), "Expected '%s', got '%s'\n", displayname, config->lpDisplayName); + ok(ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_ERROR_NORMAL, NULL, "TestGroup2", NULL, NULL, NULL, NULL, displayname2), + "ChangeServiceConfig failed (err=%d)\n", GetLastError()); + + QueryServiceConfigA(svc_handle, NULL, 0, &needed); + config = HeapReAlloc(GetProcessHeap(), 0, config, needed); + ok(QueryServiceConfigA(svc_handle, config, needed, &needed), "QueryServiceConfig failed\n"); + ok(config->lpBinaryPathName && config->lpLoadOrderGroup && config->lpDependencies && config->lpServiceStartName && + config->lpDisplayName, "Expected all string struct members to be non-NULL\n"); + ok(config->dwServiceType == (SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS), + "Expected SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, got %d\n", config->dwServiceType); + ok(config->dwStartType == SERVICE_DISABLED, "Expected SERVICE_DISABLED, got %d\n", config->dwStartType); + ok(config->dwErrorControl == SERVICE_ERROR_NORMAL, "Expected SERVICE_ERROR_NORMAL, got %d\n", config->dwErrorControl); + ok(!strcmp(config->lpBinaryPathName, pathname), "Expected '%s', got '%s'\n", pathname, config->lpBinaryPathName); + ok(!strcmp(config->lpLoadOrderGroup, "TestGroup2"), "Expected 'TestGroup2', got '%s'\n", config->lpLoadOrderGroup); + ok(config->dwTagId == 0, "Expected 0, got %d\n", config->dwTagId); + ok(!strcmp(config->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName); + ok(!strcmp(config->lpDisplayName, displayname2), "Expected '%s', got '%s'\n", displayname2, config->lpDisplayName); + + SetLastError(0xdeadbeef); ret = DeleteService(svc_handle); ok(ret, "Expected success\n"); diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl index ad0d51f..479eaf2 100644 --- a/include/wine/svcctl.idl +++ b/include/wine/svcctl.idl @@ -79,9 +79,27 @@ cpp_quote("#endif") [in,ref] POLICY_HANDLE *hService ); + /* Compatible with Windows function 0x0b */ + DWORD svcctl_ChangeServiceConfigW( + SvcCtlRpcHandle rpc_handle, + [in,ref] POLICY_HANDLE *hService, + [in] DWORD dwServiceType, + [in] DWORD dwStartType, + [in] DWORD dwErrorControl, + [in,unique,string] LPCWSTR lpBinaryPathName, + [in,unique,string] LPCWSTR lpLoadOrderGroupKey, + [in,out,unique] DWORD *lpdwTagId, + [in,unique,size_is(dwDependenciesSize)] const BYTE *lpDependencies, + [in] DWORD dwDependenciesSize, + [in,unique,string] LPCWSTR lpServiceStartName, + [in,unique,size_is(dwPasswordSize)] const BYTE *lpPassword, + [in] DWORD dwPasswordSize, + [in,unique,string] LPCWSTR lpDisplayName + ); + /* Compatible with Windows function 0x0c */ DWORD svcctl_CreateServiceW( - SvcCtlRpcHandle rpc_handle, + SvcCtlRpcHandle rpc_handle, [in] POLICY_HANDLE *hSCManager, [in] LPCWSTR lpServiceName, [in,unique] LPCWSTR lpDisplayName, diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 4aefdd9..eefd849 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -383,6 +383,113 @@ DWORD svcctl_QueryServiceConfigW( return ERROR_SUCCESS; } +DWORD svcctl_ChangeServiceConfigW( + SvcCtlRpcHandle rpc_handle, + POLICY_HANDLE *hService, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPCWSTR lpBinaryPathName, + LPCWSTR lpLoadOrderGroup, + DWORD *lpdwTagId, + const BYTE *lpDependencies, + DWORD dwDependenciesSize, + LPCWSTR lpServiceStartName, + const BYTE *lpPassword, + DWORD dwPasswordSize, + LPCWSTR lpDisplayName) +{ + service_entry new_entry; + service_entry *service; + DWORD err; + + WINE_TRACE("conn=%p (%s)\n", rpc_handle, wine_dbgstr_guid(&hService->uuid)); + if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0) + return err; + + if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize)) + return ERROR_INVALID_PARAMETER; + + /* first check if the new configuration is correct */ + lock_services(); + + if (lpDisplayName != NULL && find_service_by_displayname(lpDisplayName)) + { + unlock_services(); + return ERROR_DUPLICATE_SERVICE_NAME; + } + + new_entry = *service; + + if (dwServiceType != SERVICE_NO_CHANGE) + new_entry.config.dwServiceType = dwServiceType; + + if (dwStartType != SERVICE_NO_CHANGE) + new_entry.config.dwStartType = dwStartType; + + if (dwErrorControl != SERVICE_NO_CHANGE) + new_entry.config.dwErrorControl = dwErrorControl; + + if (lpBinaryPathName != NULL) + new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName; + + if (lpLoadOrderGroup != NULL) + new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup; + + if (lpdwTagId != NULL) + WINE_FIXME("Changing tag id not supported\n"); + + if (lpDependencies != NULL) + WINE_FIXME("Chainging dependencies not supported\n"); + + if (lpServiceStartName != NULL) + new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName; + + if (lpPassword != NULL) + WINE_FIXME("Setting password not supported\n"); + + if (lpDisplayName != NULL) + new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName; + + if (!validate_service_config(&new_entry)) + { + WINE_ERR("The configuration after the change wouldn't be valid"); + unlock_services(); + return ERROR_INVALID_PARAMETER; + } + + /* configuration OK. The strings needs to be duplicated */ + if (lpBinaryPathName != NULL) + { + HeapFree(GetProcessHeap(), 0, service->config.lpBinaryPathName); + new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName); + } + + if (lpLoadOrderGroup != NULL) + { + HeapFree(GetProcessHeap(), 0, service->config.lpLoadOrderGroup); + new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup); + } + + if (lpServiceStartName != NULL) + { + HeapFree(GetProcessHeap(), 0, service->config.lpServiceStartName); + new_entry.config.lpServiceStartName = strdupW(lpServiceStartName); + } + + if (lpDisplayName != NULL) + { + HeapFree(GetProcessHeap(), 0, service->config.lpDisplayName); + new_entry.config.lpDisplayName = strdupW(lpDisplayName); + } + + *service = new_entry; + save_service_config(service); + unlock_services(); + + return ERROR_SUCCESS; +} + DWORD svcctl_CloseServiceHandle( SvcCtlRpcHandle rpc_handle, POLICY_HANDLE *handle) diff --git a/programs/services/services.c b/programs/services/services.c index c701896..946f8b1 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -140,7 +140,7 @@ static DWORD reg_set_string_value(HKEY h } } -static DWORD save_service_config(service_entry *entry) +DWORD save_service_config(service_entry *entry) { HKEY hServicesRootKey; DWORD err; diff --git a/programs/services/services.h b/programs/services/services.h index 5dfca89..b8cf458 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -41,6 +41,7 @@ service_entry *find_service(LPCWSTR name service_entry *find_service_by_displayname(LPCWSTR name); DWORD add_service(service_entry *entry); DWORD remove_service(service_entry *entry); +DWORD save_service_config(service_entry *entry); void free_service_entry(service_entry *entry); void release_service(service_entry *service); -- 1.4.1