diff --git a/dlls/advapi32/advapi32_misc.h b/dlls/advapi32/advapi32_misc.h index e4ecfbba8ad..3e58b046465 100644 --- a/dlls/advapi32/advapi32_misc.h +++ b/dlls/advapi32/advapi32_misc.h @@ -21,6 +21,7 @@ #define __WINE_ADVAPI32MISC_H #include "ntsecapi.h" +#include "winsvc.h" const char * debugstr_sid(PSID sid) DECLSPEC_HIDDEN; BOOL ADVAPI_IsLocalComputer(LPCWSTR ServerName) DECLSPEC_HIDDEN; @@ -28,6 +29,7 @@ BOOL ADVAPI_GetComputerSid(PSID sid) DECLSPEC_HIDDEN; BOOL lookup_local_wellknown_name(const LSA_UNICODE_STRING*, PSID, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE, BOOL*) DECLSPEC_HIDDEN; BOOL lookup_local_user_name(const LSA_UNICODE_STRING*, PSID, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE, BOOL*) DECLSPEC_HIDDEN; -WCHAR *SERV_dup(const char *str); +WCHAR *SERV_dup(const char *str) DECLSPEC_HIDDEN; +NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD) DECLSPEC_HIDDEN; #endif /* __WINE_ADVAPI32MISC_H */ diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index e00085437e7..d857591af7c 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -3046,7 +3046,26 @@ DWORD WINAPI GetSecurityInfo( ULONG n1, n2; BOOL present, defaulted; - status = NtQuerySecurityObject(hObject, SecurityInfo, NULL, 0, &n1); + /* A NULL descriptor is allowed if any one of the other pointers is not NULL */ + if (!(ppsidOwner||ppsidGroup||ppDacl||ppSacl||ppSecurityDescriptor)) return ERROR_INVALID_PARAMETER; + + /* If no descriptor, we have to check that there's a pointer for the requested information */ + if( !ppSecurityDescriptor && ( + ((SecurityInfo & OWNER_SECURITY_INFORMATION) && !ppsidOwner) + || ((SecurityInfo & GROUP_SECURITY_INFORMATION) && !ppsidGroup) + || ((SecurityInfo & DACL_SECURITY_INFORMATION) && !ppDacl) + || ((SecurityInfo & SACL_SECURITY_INFORMATION) && !ppSacl) )) + return ERROR_INVALID_PARAMETER; + + switch (ObjectType) + { + case SE_SERVICE: + status = SERV_QueryServiceObjectSecurity(hObject, SecurityInfo, NULL, 0, &n1); + break; + default: + status = NtQuerySecurityObject(hObject, SecurityInfo, NULL, 0, &n1); + break; + } if (status != STATUS_BUFFER_TOO_SMALL && status != STATUS_SUCCESS) return RtlNtStatusToDosError(status); @@ -3054,7 +3073,15 @@ DWORD WINAPI GetSecurityInfo( if (!sd) return ERROR_NOT_ENOUGH_MEMORY; - status = NtQuerySecurityObject(hObject, SecurityInfo, sd, n1, &n2); + switch (ObjectType) + { + case SE_SERVICE: + status = SERV_QueryServiceObjectSecurity(hObject, SecurityInfo, sd, n1, &n2); + break; + default: + status = NtQuerySecurityObject(hObject, SecurityInfo, sd, n1, &n2); + break; + } if (status != STATUS_SUCCESS) { LocalFree(sd); diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index 07b9e4bc078..fc98880a024 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -28,6 +28,8 @@ #include #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winsvc.h" @@ -2147,17 +2149,14 @@ BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, return err == ERROR_SUCCESS; } -/****************************************************************************** - * QueryServiceObjectSecurity [ADVAPI32.@] - */ -BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService, +NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService, SECURITY_INFORMATION dwSecurityInformation, PSECURITY_DESCRIPTOR lpSecurityDescriptor, DWORD cbBufSize, LPDWORD pcbBytesNeeded) { SECURITY_DESCRIPTOR descriptor; + NTSTATUS status; DWORD size; - BOOL succ; ACL acl; FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation, @@ -2172,9 +2171,27 @@ BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService, SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE); size = cbBufSize; - succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size); + status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size); *pcbBytesNeeded = size; - return succ; + return status; +} + +/****************************************************************************** + * QueryServiceObjectSecurity [ADVAPI32.@] + */ +BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService, + SECURITY_INFORMATION dwSecurityInformation, + PSECURITY_DESCRIPTOR lpSecurityDescriptor, + DWORD cbBufSize, LPDWORD pcbBytesNeeded) +{ + NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor, + cbBufSize, pcbBytesNeeded); + if (status != STATUS_SUCCESS) + { + SetLastError(RtlNtStatusToDosError(status)); + return FALSE; + } + return TRUE; } /****************************************************************************** diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c index b6aff26cc3a..5fcd4cb15c4 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -48,6 +48,8 @@ static BOOL (WINAPI *pQueryServiceConfig2A)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD static BOOL (WINAPI *pQueryServiceConfig2W)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); static BOOL (WINAPI *pQueryServiceStatusEx)(SC_HANDLE, SC_STATUS_TYPE, LPBYTE, DWORD, LPDWORD); +static BOOL (WINAPI *pQueryServiceObjectSecurity)(SC_HANDLE, SECURITY_INFORMATION, + PSECURITY_DESCRIPTOR, DWORD, LPDWORD); static void init_function_pointers(void) { @@ -60,6 +62,7 @@ static void init_function_pointers(void) pQueryServiceConfig2A= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2A"); pQueryServiceConfig2W= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2W"); pQueryServiceStatusEx= (void*)GetProcAddress(hadvapi32, "QueryServiceStatusEx"); + pQueryServiceObjectSecurity = (void*)GetProcAddress(hadvapi32, "QueryServiceObjectSecurity"); } static void test_open_scm(void) @@ -1756,7 +1759,7 @@ static void test_close(void) static void test_sequence(void) { SC_HANDLE scm_handle, svc_handle; - BOOL ret; + BOOL ret, is_nt4; QUERY_SERVICE_CONFIGA *config; DWORD given, needed; static const CHAR servicename [] = "Winetest"; @@ -1780,6 +1783,9 @@ static void test_sequence(void) ok(scm_handle != NULL, "Could not get a handle to the manager: %d\n", GetLastError()); if (!scm_handle) return; + svc_handle = OpenServiceA(scm_handle, NULL, GENERIC_READ); + is_nt4=(svc_handle == NULL && GetLastError() == ERROR_INVALID_PARAMETER); + CloseServiceHandle(svc_handle); /* Create a dummy service */ SetLastError(0xdeadbeef); @@ -1817,8 +1823,44 @@ static void test_sequence(void) PSID sidOwner, sidGroup; PACL dacl, sacl; PSECURITY_DESCRIPTOR pSD; - HRESULT retval = pGetSecurityInfo(svc_handle,SE_SERVICE,DACL_SECURITY_INFORMATION,&sidOwner,&sidGroup,&dacl,&sacl,&pSD); - todo_wine ok(ERROR_SUCCESS == retval, "Expected GetSecurityInfo to succeed: result %d\n",retval); + DWORD error, n1, n2; + HRESULT retval; + BOOL bret; + + /* Test using GetSecurityInfo to obtain security information */ + retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, &sidOwner, + &sidGroup, &dacl, &sacl, &pSD); + LocalFree(pSD); + ok(retval == ERROR_SUCCESS, "Expected GetSecurityInfo to succeed: result %d\n", retval); + retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, + NULL, NULL, NULL, &pSD); + LocalFree(pSD); + ok(retval == ERROR_SUCCESS, "Expected GetSecurityInfo to succeed: result %d\n", retval); + if (!is_nt4) + { + retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, + NULL, &dacl, NULL, NULL); + ok(retval == ERROR_SUCCESS, "Expected GetSecurityInfo to succeed: result %d\n", retval); + SetLastError(0xdeadbeef); + retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, + NULL, NULL, NULL, NULL); + error = GetLastError(); + ok(retval == ERROR_INVALID_PARAMETER, "Expected GetSecurityInfo to fail: result %d\n", retval); + ok(error == 0xdeadbeef, "Unexpected last error %d\n", error); + } + else + win_skip("A NULL security descriptor in GetSecurityInfo results in an exception on NT4.\n"); + + /* Test using QueryServiceObjectSecurity to obtain security information */ + SetLastError(0xdeadbeef); + bret = pQueryServiceObjectSecurity(svc_handle, DACL_SECURITY_INFORMATION, pSD, 0, &n1); + error = GetLastError(); + ok(!bret, "Expected QueryServiceObjectSecurity to fail: result %d\n", bret); + ok(error == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", error); + pSD = LocalAlloc(0, n1); + bret = pQueryServiceObjectSecurity(svc_handle, DACL_SECURITY_INFORMATION, pSD, n1, &n2); + ok(bret, "Expected QueryServiceObjectSecurity to succeed: result %d\n", bret); + LocalFree(pSD); } }