advapi32: Fix QueryServiceConfig2 on Wow64.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Hans Leidekker 2017-11-07 14:10:41 +01:00 committed by Alexandre Julliard
parent 445996d31b
commit 251c9ccff7
3 changed files with 94 additions and 32 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);
*needed = sizeof(*descr);
service_lock(service->service_entry);
if (service->service_entry->description)
total_size += strlenW(service->service_entry->description) * sizeof(WCHAR);
*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);