Hans Leidekker : advapi32: Fix QueryServiceConfig2 on Wow64.

Alexandre Julliard julliard at winehq.org
Wed Nov 8 16:01:10 CST 2017


Module: wine
Branch: master
Commit: 251c9ccff7077921a5ddd5b6616e104869d16501
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=251c9ccff7077921a5ddd5b6616e104869d16501

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Tue Nov  7 14:10:41 2017 +0100

advapi32: Fix QueryServiceConfig2 on Wow64.

Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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 78491ae..3f2fb93 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 7c5df7d..c14cd6b 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 a1d3c9e..20c5a27 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);




More information about the wine-cvs mailing list