From 8ce582105c47e7c2b58dc06770c5dba00faa89a3 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 19 Oct 2014 06:47:11 +0200
Subject: shell32: Set the default security attributes for user shell folders. (try 7)

Based on a patch by Erich E. Hoover.
---
 dlls/shell32/shellpath.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 1 deletion(-)

diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index f92d56e..b6ac04b 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -2200,6 +2200,80 @@ cleanup:
     return hr;
 }
 
+static PSID get_user_sid( TOKEN_USER **user )
+{
+    DWORD user_size = 0;
+    HANDLE token;
+    if (OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token) ||
+        (GetLastError() == ERROR_NO_TOKEN &&
+        OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token)))
+    {
+        if (!GetTokenInformation(token, TokenUser, NULL, 0, &user_size) &&
+            GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
+            (*user = HeapAlloc(GetProcessHeap(), 0, user_size)))
+        {
+            if (GetTokenInformation(token, TokenUser, *user, user_size, &user_size))
+            {
+                CloseHandle(token);
+                return (*user)->User.Sid;
+            }
+            HeapFree(GetProcessHeap(), 0, *user);
+        }
+        CloseHandle(token);
+    }
+    return NULL;
+}
+
+static PSID get_admin_sid( void )
+{
+    DWORD sid_size = 0;
+    PSID admin_sid;
+    if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, NULL, &sid_size) &&
+        GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
+        (admin_sid = HeapAlloc(GetProcessHeap(), 0, sid_size)))
+    {
+        if (CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, admin_sid, &sid_size))
+            return admin_sid;
+        HeapFree(GetProcessHeap(), 0, admin_sid);
+    }
+    return NULL;
+}
+
+static PSECURITY_DESCRIPTOR _SHGetUserSecurityDescriptor( void )
+{
+    PSID user_sid, admin_sid = NULL;
+    SECURITY_DESCRIPTOR *sd = NULL;
+    TOKEN_USER *user = NULL;
+
+    if ((user_sid  = get_user_sid( &user )) &&
+        (admin_sid = get_admin_sid()))
+    {
+        DWORD dacl_size = sizeof(ACL) + 2 * sizeof(ACE_HEADER) + 2 * sizeof(DWORD) +
+                          GetLengthSid(user_sid) + GetLengthSid(admin_sid);
+        if ((sd = HeapAlloc(GetProcessHeap(), 0, sizeof(SECURITY_DESCRIPTOR) + dacl_size)))
+        {
+            PACL dacl = (ACL *)(sd + 1);
+            if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION) ||
+                !InitializeAcl(dacl, dacl_size, ACL_REVISION) ||
+                !AddAccessAllowedAceEx(dacl, ACL_REVISION,
+                                       OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
+                                       GENERIC_ALL, user_sid) ||
+                !AddAccessAllowedAceEx(dacl, ACL_REVISION,
+                                       OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
+                                       GENERIC_ALL, admin_sid) ||
+                !SetSecurityDescriptorDacl(sd, TRUE, dacl, FALSE))
+            {
+                HeapFree(GetProcessHeap(), 0, sd);
+                sd = NULL;
+            }
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, admin_sid);
+    HeapFree(GetProcessHeap(), 0, user);
+    return sd;
+}
+
 /*************************************************************************
  * SHGetFolderPathAndSubDirW		[SHELL32.@]
  */
@@ -2211,6 +2285,8 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
 	LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */
 	LPWSTR pszPath)    /* [O] converted path */
 {
+    SECURITY_ATTRIBUTES sa, *sec = NULL;
+    PSECURITY_DESCRIPTOR sd = NULL;
     HRESULT    hr;
     WCHAR      szBuildPath[MAX_PATH], szTemp[MAX_PATH];
     DWORD      folder = nFolder & CSIDL_FOLDER_MASK;
@@ -2323,8 +2399,25 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
         goto end;
     }
 
+    /* build the appropriate security attributes for the directory */
+    switch (type)
+    {
+        case CSIDL_Type_User:
+            sd = _SHGetUserSecurityDescriptor();
+            break;
+        default:
+            break;
+    }
+    if (sd)
+    {
+        sa.nLength = sizeof(sa);
+        sa.lpSecurityDescriptor = sd;
+        sa.bInheritHandle = TRUE;
+        sec = &sa;
+    }
+
     /* create directory/directories */
-    ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL);
+    ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, sec);
     if (ret && ret != ERROR_ALREADY_EXISTS)
     {
         ERR("Failed to create directory %s.\n", debugstr_w(szBuildPath));
@@ -2334,6 +2427,7 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
 
     TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath));
 end:
+    HeapFree(GetProcessHeap(), 0, sd);
     TRACE("returning 0x%08x (final path is %s)\n", hr, debugstr_w(szBuildPath));
     return hr;
 }
-- 
2.1.2

