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; BOOL ret;
LPBYTE bufferW = NULL; LPBYTE bufferW = NULL;
TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed);
if(buffer && size) if(buffer && size)
bufferW = heap_alloc(size); bufferW = heap_alloc(size);
@ -1591,24 +1593,42 @@ cleanup:
BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer, BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
DWORD size, LPDWORD needed) DWORD size, LPDWORD needed)
{ {
BYTE *bufptr;
DWORD err; 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); FIXME("Level %d not implemented\n", dwLevel);
SetLastError(ERROR_INVALID_LEVEL); SetLastError(ERROR_INVALID_LEVEL);
return FALSE; return FALSE;
} }
if(!buffer && size) { if (!needed)
{
SetLastError(ERROR_INVALID_ADDRESS); SetLastError(ERROR_INVALID_ADDRESS);
return FALSE; return FALSE;
} }
TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
__TRY __TRY
{ {
err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed); err = svcctl_QueryServiceConfig2W(hService, dwLevel, bufptr, size, needed);
} }
__EXCEPT(rpc_filter) __EXCEPT(rpc_filter)
{ {
@ -1616,22 +1636,53 @@ BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffe
} }
__ENDTRY __ENDTRY
if (err != ERROR_SUCCESS)
{
SetLastError( err );
return FALSE;
}
switch (dwLevel) switch (dwLevel)
{ {
case SERVICE_CONFIG_DESCRIPTION: 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; heap_free( bufptr );
if (descr->lpDescription) /* make it an absolute pointer */ SetLastError( err );
descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription); return FALSE;
break;
} }
/* 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; return TRUE;

View File

@ -225,6 +225,12 @@ struct enum_service_status_process
SERVICE_STATUS_PROCESS service_status_process; SERVICE_STATUS_PROCESS service_status_process;
}; };
struct service_description
{
USHORT size;
WCHAR description[1];
};
typedef struct _SERVICE_RPC_REQUIRED_PRIVILEGES_INFO { typedef struct _SERVICE_RPC_REQUIRED_PRIVILEGES_INFO {
DWORD cbRequiredPrivileges; DWORD cbRequiredPrivileges;
[size_is(cbRequiredPrivileges)] BYTE *pRequiredPrivileges; [size_is(cbRequiredPrivileges)] BYTE *pRequiredPrivileges;

View File

@ -879,27 +879,32 @@ DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
switch (level) switch (level)
{ {
case SERVICE_CONFIG_DESCRIPTION: 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); service_lock(service->service_entry);
*needed = sizeof(*descr); 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) if (service->service_entry->description)
*needed += (strlenW(service->service_entry->description) + 1) * sizeof(WCHAR);
if (size >= *needed)
{ {
if (service->service_entry->description) strcpyW( desc->description, service->service_entry->description );
{ desc->size = total_size - FIELD_OFFSET(struct service_description, description);
/* store a buffer offset instead of a pointer */ }
descr->lpDescription = (WCHAR *)((BYTE *)(descr + 1) - buffer); else
strcpyW( (WCHAR *)(descr + 1), service->service_entry->description ); {
} desc->description[0] = 0;
else descr->lpDescription = NULL; 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: case SERVICE_CONFIG_PRESHUTDOWN_INFO:
service_lock(service->service_entry); service_lock(service->service_entry);