[MSIEXEC] Sync with Wine Staging 2.16. CORE-13762
[reactos.git] / base / system / services / config.c
index de2bc5b..2099d64 100644 (file)
 /* INCLUDES *****************************************************************/
 
 #include "services.h"
+#include <ntsecapi.h>
 
 #define NDEBUG
 #include <debug.h>
 
+
 /* FUNCTIONS *****************************************************************/
 
 
@@ -98,9 +100,9 @@ ScmWriteDependencies(HKEY hServiceKey,
                      DWORD dwDependenciesLength)
 {
     DWORD dwError = ERROR_SUCCESS;
-    DWORD dwGroupLength = 0;
-    DWORD dwServiceLength = 0;
-    DWORD dwLength;
+    SIZE_T cchGroupLength = 0;
+    SIZE_T cchServiceLength = 0;
+    SIZE_T cchLength;
     LPWSTR lpGroupDeps;
     LPWSTR lpServiceDeps;
     LPCWSTR lpSrc;
@@ -125,46 +127,47 @@ ScmWriteDependencies(HKEY hServiceKey,
         lpDst = lpGroupDeps;
         while (*lpSrc != 0)
         {
-            dwLength = wcslen(lpSrc) + 1;
+            cchLength = wcslen(lpSrc) + 1;
             if (*lpSrc == SC_GROUP_IDENTIFIERW)
             {
                 lpSrc++;
-                dwGroupLength += dwLength;
+                cchLength--;
+                cchGroupLength += cchLength;
                 wcscpy(lpDst, lpSrc);
-                lpDst = lpDst + dwLength;
+                lpDst = lpDst + cchLength;
             }
 
-            lpSrc = lpSrc + dwLength;
+            lpSrc = lpSrc + cchLength;
         }
         *lpDst = 0;
         lpDst++;
-        dwGroupLength++;
+        cchGroupLength++;
 
         lpSrc = lpDependencies;
         lpServiceDeps = lpDst;
         while (*lpSrc != 0)
         {
-            dwLength = wcslen(lpSrc) + 1;
+            cchLength = wcslen(lpSrc) + 1;
             if (*lpSrc != SC_GROUP_IDENTIFIERW)
             {
-                dwServiceLength += dwLength;
+                cchServiceLength += cchLength;
                 wcscpy(lpDst, lpSrc);
-                lpDst = lpDst + dwLength;
+                lpDst = lpDst + cchLength;
             }
 
-            lpSrc = lpSrc + dwLength;
+            lpSrc = lpSrc + cchLength;
         }
         *lpDst = 0;
-        dwServiceLength++;
+        cchServiceLength++;
 
-        if (dwGroupLength > 1)
+        if (cchGroupLength > 1)
         {
             dwError = RegSetValueExW(hServiceKey,
                                      L"DependOnGroup",
                                      0,
                                      REG_MULTI_SZ,
                                      (LPBYTE)lpGroupDeps,
-                                     dwGroupLength * sizeof(WCHAR));
+                                     (DWORD)(cchGroupLength * sizeof(WCHAR)));
         }
         else
         {
@@ -174,14 +177,14 @@ ScmWriteDependencies(HKEY hServiceKey,
 
         if (dwError == ERROR_SUCCESS)
         {
-            if (dwServiceLength > 1)
+            if (cchServiceLength > 1)
             {
                 dwError = RegSetValueExW(hServiceKey,
                                          L"DependOnService",
                                          0,
                                          REG_MULTI_SZ,
                                          (LPBYTE)lpServiceDeps,
-                                         dwServiceLength * sizeof(WCHAR));
+                                         (DWORD)(cchServiceLength * sizeof(WCHAR)));
             }
             else
             {
@@ -246,19 +249,17 @@ ScmIsDeleteFlagSet(HKEY hServiceKey)
 
 DWORD
 ScmReadString(HKEY hServiceKey,
-              LPWSTR lpValueName,
+              LPCWSTR lpValueName,
               LPWSTR *lpValue)
 {
-    DWORD dwError;
-    DWORD dwSize;
-    DWORD dwType;
-    DWORD dwSizeNeeded;
-    LPWSTR expanded = NULL;
+    DWORD dwError = 0;
+    DWORD dwSize = 0;
+    DWORD dwType = 0;
     LPWSTR ptr = NULL;
+    LPWSTR expanded = NULL;
 
     *lpValue = NULL;
 
-    dwSize = 0;
     dwError = RegQueryValueExW(hServiceKey,
                                lpValueName,
                                0,
@@ -268,7 +269,7 @@ ScmReadString(HKEY hServiceKey,
     if (dwError != ERROR_SUCCESS)
         return dwError;
 
-    ptr = HeapAlloc(GetProcessHeap(), 0, dwSize);
+    ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
     if (ptr == NULL)
         return ERROR_NOT_ENOUGH_MEMORY;
 
@@ -279,40 +280,48 @@ ScmReadString(HKEY hServiceKey,
                                (LPBYTE)ptr,
                                &dwSize);
     if (dwError != ERROR_SUCCESS)
-        goto done;
+    {
+        HeapFree(GetProcessHeap(), 0, ptr);
+        return dwError;
+    }
 
     if (dwType == REG_EXPAND_SZ)
     {
         /* Expand the value... */
-        dwSizeNeeded = ExpandEnvironmentStringsW((LPCWSTR)ptr, NULL, 0);
-        if (dwSizeNeeded == 0)
+        dwSize = ExpandEnvironmentStringsW(ptr, NULL, 0);
+        if (dwSize > 0)
         {
-            dwError = GetLastError();
-            goto done;
+            expanded = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR));
+            if (expanded)
+            {
+                if (dwSize == ExpandEnvironmentStringsW(ptr, expanded, dwSize))
+                {
+                    *lpValue = expanded;
+                    dwError = ERROR_SUCCESS;
+                }
+                else
+                {
+                    dwError = GetLastError();
+                    HeapFree(GetProcessHeap(), 0, expanded);
+                }
+            }
+            else
+            {
+                dwError = ERROR_NOT_ENOUGH_MEMORY;
+            }
         }
-        expanded = HeapAlloc(GetProcessHeap(), 0, dwSizeNeeded * sizeof(WCHAR));
-        if (dwSizeNeeded < ExpandEnvironmentStringsW((LPCWSTR)ptr, expanded, dwSizeNeeded))
+        else
         {
             dwError = GetLastError();
-            goto done;
         }
-        *lpValue = expanded;
+
         HeapFree(GetProcessHeap(), 0, ptr);
-        dwError = ERROR_SUCCESS;
     }
     else
     {
         *lpValue = ptr;
     }
 
-done:
-    if (dwError != ERROR_SUCCESS)
-    {
-        HeapFree(GetProcessHeap(), 0, ptr);
-        if (expanded)
-            HeapFree(GetProcessHeap(), 0, expanded);
-    }
-
     return dwError;
 }
 
@@ -324,12 +333,12 @@ ScmReadDependencies(HKEY hServiceKey,
 {
     LPWSTR lpGroups = NULL;
     LPWSTR lpServices = NULL;
-    DWORD dwGroupsLength = 0;
-    DWORD dwServicesLength = 0;
+    SIZE_T cchGroupsLength = 0;
+    SIZE_T cchServicesLength = 0;
     LPWSTR lpSrc;
     LPWSTR lpDest;
-    DWORD len;
-    DWORD dwTotalLength;
+    SIZE_T cchLength;
+    SIZE_T cchTotalLength;
 
     *lpDependencies = NULL;
     *lpdwDependenciesLength = 0;
@@ -356,10 +365,10 @@ ScmReadDependencies(HKEY hServiceKey,
         {
             DPRINT("  %S\n", lpSrc);
 
-            len = wcslen(lpSrc) + 1;
-            dwGroupsLength += len + 1;
+            cchLength = wcslen(lpSrc) + 1;
+            cchGroupsLength += cchLength + 1;
 
-            lpSrc = lpSrc + len;
+            lpSrc = lpSrc + cchLength;
         }
     }
 
@@ -371,18 +380,18 @@ ScmReadDependencies(HKEY hServiceKey,
         {
             DPRINT("  %S\n", lpSrc);
 
-            len = wcslen(lpSrc) + 1;
-            dwServicesLength += len;
+            cchLength = wcslen(lpSrc) + 1;
+            cchServicesLength += cchLength;
 
-            lpSrc = lpSrc + len;
+            lpSrc = lpSrc + cchLength;
         }
     }
 
-    dwTotalLength = dwGroupsLength + dwServicesLength + 1;
-    DPRINT("dwTotalLength: %lu\n", dwTotalLength);
+    cchTotalLength = cchGroupsLength + cchServicesLength + 1;
+    DPRINT("cchTotalLength: %lu\n", cchTotalLength);
 
     /* Allocate the common buffer for the dependencies */
-    *lpDependencies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwTotalLength * sizeof(WCHAR));
+    *lpDependencies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cchTotalLength * sizeof(WCHAR));
     if (*lpDependencies == NULL)
     {
         if (lpGroups)
@@ -395,7 +404,7 @@ ScmReadDependencies(HKEY hServiceKey,
     }
 
     /* Return the allocated buffer length in characters */
-    *lpdwDependenciesLength = dwTotalLength;
+    *lpdwDependenciesLength = (DWORD)cchTotalLength;
 
     /* Copy the service dependencies into the common buffer */
     lpDest = *lpDependencies;
@@ -403,9 +412,9 @@ ScmReadDependencies(HKEY hServiceKey,
     {
         memcpy(lpDest,
                lpServices,
-               dwServicesLength * sizeof(WCHAR));
+               cchServicesLength * sizeof(WCHAR));
 
-        lpDest = lpDest + dwServicesLength;
+        lpDest = lpDest + cchServicesLength;
     }
 
     /* Copy the group dependencies into the common buffer */
@@ -414,15 +423,15 @@ ScmReadDependencies(HKEY hServiceKey,
         lpSrc = lpGroups;
         while (*lpSrc != 0)
         {
-            len = wcslen(lpSrc) + 1;
+            cchLength = wcslen(lpSrc) + 1;
 
             *lpDest = SC_GROUP_IDENTIFIERW;
             lpDest++;
 
             wcscpy(lpDest, lpSrc);
 
-            lpDest = lpDest + len;
-            lpSrc = lpSrc + len;
+            lpDest = lpDest + cchLength;
+            lpSrc = lpSrc + cchLength;
         }
     }
 
@@ -436,4 +445,236 @@ ScmReadDependencies(HKEY hServiceKey,
     return ERROR_SUCCESS;
 }
 
+
+DWORD
+ScmSetServicePassword(
+    IN PCWSTR pszServiceName,
+    IN PCWSTR pszPassword)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    LSA_HANDLE PolicyHandle = NULL;
+    UNICODE_STRING ServiceName = {0, 0, NULL};
+    UNICODE_STRING Password;
+    NTSTATUS Status;
+    DWORD dwError = ERROR_SUCCESS;
+
+    RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
+
+    Status = LsaOpenPolicy(NULL,
+                           &ObjectAttributes,
+                           POLICY_CREATE_SECRET,
+                           &PolicyHandle);
+    if (!NT_SUCCESS(Status))
+        return RtlNtStatusToDosError(Status);
+
+    ServiceName.Length = (wcslen(pszServiceName) + 4) * sizeof(WCHAR);
+    ServiceName.MaximumLength = ServiceName.Length + sizeof(WCHAR);
+    ServiceName.Buffer = HeapAlloc(GetProcessHeap(),
+                                   HEAP_ZERO_MEMORY,
+                                   ServiceName.MaximumLength);
+    if (ServiceName.Buffer == NULL)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    wcscpy(ServiceName.Buffer, L"_SC_");
+    wcscat(ServiceName.Buffer, pszServiceName);
+
+    RtlInitUnicodeString(&Password, pszPassword);
+
+    Status = LsaStorePrivateData(PolicyHandle,
+                                 &ServiceName,
+                                 pszPassword ? &Password : NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        dwError = RtlNtStatusToDosError(Status);
+        goto done;
+    }
+
+done:
+    if (ServiceName.Buffer != NULL)
+        HeapFree(GetProcessHeap(), 0, ServiceName.Buffer);
+
+    if (PolicyHandle != NULL)
+        LsaClose(PolicyHandle);
+
+    return dwError;
+}
+
+
+DWORD
+ScmWriteSecurityDescriptor(
+    _In_ HKEY hServiceKey,
+    _In_ PSECURITY_DESCRIPTOR pSecurityDescriptor)
+{
+    HKEY hSecurityKey = NULL;
+    DWORD dwDisposition;
+    DWORD dwError;
+
+    DPRINT("ScmWriteSecurityDescriptor(%p %p)\n", hServiceKey, pSecurityDescriptor);
+
+    dwError = RegCreateKeyExW(hServiceKey,
+                              L"Security",
+                              0,
+                              NULL,
+                              REG_OPTION_NON_VOLATILE,
+                              KEY_SET_VALUE,
+                              NULL,
+                              &hSecurityKey,
+                              &dwDisposition);
+    if (dwError != ERROR_SUCCESS)
+        return dwError;
+
+    dwError = RegSetValueExW(hSecurityKey,
+                             L"Security",
+                             0,
+                             REG_BINARY,
+                             (LPBYTE)pSecurityDescriptor,
+                             RtlLengthSecurityDescriptor(pSecurityDescriptor));
+
+    RegCloseKey(hSecurityKey);
+
+    return dwError;
+}
+
+
+DWORD
+ScmReadSecurityDescriptor(
+    _In_ HKEY hServiceKey,
+    _Out_ PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
+{
+    PSECURITY_DESCRIPTOR pRelativeSD = NULL;
+    HKEY hSecurityKey = NULL;
+    DWORD dwBufferLength = 0;
+    DWORD dwType;
+    DWORD dwError;
+
+    DPRINT("ScmReadSecurityDescriptor(%p %p)\n", hServiceKey, ppSecurityDescriptor);
+
+    *ppSecurityDescriptor = NULL;
+
+    dwError = RegOpenKeyExW(hServiceKey,
+                            L"Security",
+                            0,
+                            KEY_QUERY_VALUE,
+                            &hSecurityKey);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT("RegOpenKeyExW() failed (Error %lu)\n", dwError);
+
+        /* Do not fail if the Security key does not exist */
+        if (dwError == ERROR_FILE_NOT_FOUND)
+            dwError = ERROR_SUCCESS;
+        goto done;
+    }
+
+    dwError = RegQueryValueExW(hSecurityKey,
+                               L"Security",
+                               0,
+                               &dwType,
+                               NULL,
+                               &dwBufferLength);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT("RegQueryValueExW() failed (Error %lu)\n", dwError);
+
+        /* Do not fail if the Security value does not exist */
+        if (dwError == ERROR_FILE_NOT_FOUND)
+            dwError = ERROR_SUCCESS;
+        goto done;
+    }
+
+    DPRINT("dwBufferLength: %lu\n", dwBufferLength);
+    pRelativeSD = RtlAllocateHeap(RtlGetProcessHeap(),
+                                  HEAP_ZERO_MEMORY,
+                                  dwBufferLength);
+    if (pRelativeSD == NULL)
+    {
+        return ERROR_OUTOFMEMORY;
+    }
+
+    DPRINT("pRelativeSD: %lu\n", pRelativeSD);
+    dwError = RegQueryValueExW(hSecurityKey,
+                               L"Security",
+                               0,
+                               &dwType,
+                               (LPBYTE)pRelativeSD,
+                               &dwBufferLength);
+    if (dwError != ERROR_SUCCESS)
+    {
+        goto done;
+    }
+
+    *ppSecurityDescriptor = pRelativeSD;
+
+done:
+    if (dwError != ERROR_SUCCESS && pRelativeSD != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, pRelativeSD);
+
+    if (hSecurityKey != NULL)
+        RegCloseKey(hSecurityKey);
+
+    return dwError;
+}
+
+
+DWORD
+ScmDeleteRegKey(
+    _In_ HKEY hKey,
+    _In_ PCWSTR pszSubKey)
+{
+    DWORD dwMaxSubkeyLen, dwMaxValueLen;
+    DWORD dwMaxLen, dwSize;
+    PWSTR pszName = NULL;
+    HKEY hSubKey;
+    DWORD dwError;
+
+    dwError = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey);
+    if (dwError != ERROR_SUCCESS)
+        return dwError;
+
+    /* Get maximum length of key and value names */
+    dwError = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
+                               &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
+    if (dwError != ERROR_SUCCESS)
+        goto done;
+
+    dwMaxSubkeyLen++;
+    dwMaxValueLen++;
+    dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
+
+    /* Allocate the name buffer */
+    pszName = HeapAlloc(GetProcessHeap(), 0, dwMaxLen * sizeof(WCHAR));
+    if (pszName == NULL)
+    {
+        dwError = ERROR_NOT_ENOUGH_MEMORY;
+        goto done;
+    }
+
+    /* Recursively delete all the subkeys */
+    while (TRUE)
+    {
+        dwSize = dwMaxLen;
+        if (RegEnumKeyExW(hSubKey, 0, pszName, &dwSize,
+                          NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+        {
+            break;
+        }
+
+        dwError = ScmDeleteRegKey(hSubKey, pszName);
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+    }
+
+done:
+    if (pszName != NULL)
+        HeapFree(GetProcessHeap(), 0, pszName);
+
+    RegCloseKey(hSubKey);
+
+    /* Finally delete the key */
+    if (dwError == ERROR_SUCCESS)
+        dwError = RegDeleteKeyW(hKey, pszSubKey);
+
+    return dwError;
+}
+
 /* EOF */