[3/3] advapi32: Fix QueryServiceConfig2 on Wow64.
Hans Leidekker
hans at codeweavers.com
Tue Nov 7 07:10:41 CST 2017
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/advapi32/service.c | 83 +++++++++++++++++++++++++++++++++++++++----------
include/wine/svcctl.idl | 6 ++++
programs/services/rpc.c | 37 ++++++++++++----------
3 files changed, 94 insertions(+), 32 deletions(-)
diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index 78491aed13..3f2fb93d68 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -1543,6 +1543,8 @@ BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffe
BOOL ret;
LPBYTE bufferW = NULL;
+ TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed);
+
if(buffer && size)
bufferW = heap_alloc(size);
@@ -1591,24 +1593,42 @@ cleanup:
BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
DWORD size, LPDWORD needed)
{
+ BYTE *bufptr;
DWORD err;
- if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
+ TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed);
+
+ if (!buffer && size)
+ {
+ SetLastError(ERROR_INVALID_ADDRESS);
+ return FALSE;
+ }
+
+ switch (dwLevel)
+ {
+ case SERVICE_CONFIG_DESCRIPTION:
+ if (!(bufptr = heap_alloc( size ))) return ERROR_OUTOFMEMORY;
+ break;
+
+ case SERVICE_CONFIG_PRESHUTDOWN_INFO:
+ bufptr = buffer;
+ break;
+
+ default:
FIXME("Level %d not implemented\n", dwLevel);
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
- if(!buffer && size) {
+ if (!needed)
+ {
SetLastError(ERROR_INVALID_ADDRESS);
return FALSE;
}
- TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
-
__TRY
{
- err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
+ err = svcctl_QueryServiceConfig2W(hService, dwLevel, bufptr, size, needed);
}
__EXCEPT(rpc_filter)
{
@@ -1616,22 +1636,53 @@ BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffe
}
__ENDTRY
- if (err != ERROR_SUCCESS)
- {
- SetLastError( err );
- return FALSE;
- }
-
switch (dwLevel)
{
case SERVICE_CONFIG_DESCRIPTION:
- if (buffer)
+ {
+ SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer;
+ struct service_description *s = (struct service_description *)bufptr;
+
+ if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
{
- SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
- if (descr->lpDescription) /* make it an absolute pointer */
- descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
- break;
+ heap_free( bufptr );
+ SetLastError( err );
+ return FALSE;
+ }
+
+ /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
+ if (*needed == sizeof(*s)) *needed = sizeof(*desc);
+ else
+ *needed = *needed - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
+
+ if (size < *needed)
+ {
+ heap_free( bufptr );
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
}
+ if (desc)
+ {
+ if (!s->size) desc->lpDescription = NULL;
+ else
+ {
+ desc->lpDescription = (WCHAR *)(desc + 1);
+ memcpy( desc->lpDescription, s->description, s->size );
+ }
+ }
+ heap_free( bufptr );
+ break;
+ }
+ case SERVICE_CONFIG_PRESHUTDOWN_INFO:
+ if (err != ERROR_SUCCESS)
+ {
+ SetLastError( err );
+ return FALSE;
+ }
+ break;
+
+ default:
+ break;
}
return TRUE;
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
index 7c5df7d961..c14cd6bb50 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -225,6 +225,12 @@ struct enum_service_status_process
SERVICE_STATUS_PROCESS service_status_process;
};
+struct service_description
+{
+ USHORT size;
+ WCHAR description[1];
+};
+
typedef struct _SERVICE_RPC_REQUIRED_PRIVILEGES_INFO {
DWORD cbRequiredPrivileges;
[size_is(cbRequiredPrivileges)] BYTE *pRequiredPrivileges;
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index a1d3c9e6cc..20c5a2761f 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -879,27 +879,32 @@ DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
switch (level)
{
case SERVICE_CONFIG_DESCRIPTION:
- {
- SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
+ {
+ struct service_description *desc = (struct service_description *)buffer;
+ DWORD total_size = sizeof(*desc);
+
+ service_lock(service->service_entry);
+ if (service->service_entry->description)
+ total_size += strlenW(service->service_entry->description) * sizeof(WCHAR);
- service_lock(service->service_entry);
- *needed = sizeof(*descr);
+ *needed = total_size;
+ if (size >= total_size)
+ {
if (service->service_entry->description)
- *needed += (strlenW(service->service_entry->description) + 1) * sizeof(WCHAR);
- if (size >= *needed)
{
- if (service->service_entry->description)
- {
- /* store a buffer offset instead of a pointer */
- descr->lpDescription = (WCHAR *)((BYTE *)(descr + 1) - buffer);
- strcpyW( (WCHAR *)(descr + 1), service->service_entry->description );
- }
- else descr->lpDescription = NULL;
+ strcpyW( desc->description, service->service_entry->description );
+ desc->size = total_size - FIELD_OFFSET(struct service_description, description);
+ }
+ else
+ {
+ desc->description[0] = 0;
+ desc->size = 0;
}
- else err = ERROR_INSUFFICIENT_BUFFER;
- service_unlock(service->service_entry);
}
- break;
+ else err = ERROR_INSUFFICIENT_BUFFER;
+ service_unlock(service->service_entry);
+ }
+ break;
case SERVICE_CONFIG_PRESHUTDOWN_INFO:
service_lock(service->service_entry);
--
2.11.0
More information about the wine-patches
mailing list