changeset 983:427e2e18b8c8

Move Shell functions into util Due to a bug in mingw only one c file may include shlobj.h as there is an unguarded inline definition in there leading to multiple definition errors. Thus the get_program_data get_program_files utility functions.
author Andre Heinecke <andre.heinecke@intevation.de>
date Fri, 29 Aug 2014 17:11:35 +0200
parents 85c497b45488
children faf58e9f518b
files cinst/nssstore_win.c common/util.c common/util.h
diffstat 3 files changed, 207 insertions(+), 151 deletions(-) [+]
line wrap: on
line diff
--- a/cinst/nssstore_win.c	Fri Aug 29 16:08:50 2014 +0200
+++ b/cinst/nssstore_win.c	Fri Aug 29 17:11:35 2014 +0200
@@ -47,7 +47,6 @@
 #include <io.h>
 #include <accctrl.h>
 #include <aclapi.h>
-#include <shlobj.h>
 
 #include "logging.h"
 #include "util.h"
@@ -735,147 +734,6 @@
   return true;
 }
 
-/**@brief Create a directory with restricted access rights
-  *
-  * This creates a security attributes structure that restricts
-  * write access to the Administrators group but allows everyone to read files
-  * in that directory.
-  * Basically a very complicated version of mkdir path -m 644
-  *
-  * If the directory exists the permissions of that directory are checked if
-  * they are acceptable and true or false is returned accordingly.
-  *
-  * Code based on msdn example:
-  * http://msdn.microsoft.com/en-us/library/windows/desktop/aa446595%28v=vs.85%29.aspx
-  *
-  * @param[in] path Path of the directory to create
-  *
-  * @returns true on success of if the directory exists, false on error
-  */
-bool
-create_restricted_directory (LPWSTR path)
-{
-  bool retval = false;
-  PSID everyone_SID = NULL,
-       admin_SID = NULL;
-  PACL access_control_list = NULL;
-  PSECURITY_DESCRIPTOR descriptor = NULL;
-  EXPLICIT_ACCESS explicit_access[2];
-  SID_IDENTIFIER_AUTHORITY world_identifier = {SECURITY_WORLD_SID_AUTHORITY},
-                           admin_identifier = {SECURITY_NT_AUTHORITY};
-  SECURITY_ATTRIBUTES security_attributes;
-
-  ZeroMemory(&security_attributes, sizeof(security_attributes));
-  ZeroMemory(&explicit_access, 2 * sizeof(EXPLICIT_ACCESS));
-
-  /* Create a well-known SID for the Everyone group. */
-  if(!AllocateAndInitializeSid(&world_identifier, /* top-level identifier */
-                               1, /* subauthorties count */
-                               SECURITY_WORLD_RID, /* Only one authority */
-                               0, 0, 0, 0, 0, 0, 0, /* No other authorities*/
-                               &everyone_SID))
-    {
-      PRINTLASTERROR ("Failed to allocate world sid.\n");
-      return false;
-    }
-
-  /* Initialize the first EXPLICIT_ACCESS structure for an ACE.
-     to allow everyone read access */
-  explicit_access[0].grfAccessPermissions = GENERIC_READ; /* Give read access */
-  explicit_access[0].grfAccessMode = SET_ACCESS; /* Overwrite other access for all users */
-  explicit_access[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; /* make it stick */
-  explicit_access[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
-  explicit_access[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
-  explicit_access[0].Trustee.ptstrName  = (LPTSTR) everyone_SID;
-
-  /* Create the SID for the BUILTIN\Administrators group. */
-  if(!AllocateAndInitializeSid(&admin_identifier,
-                               2,
-                               SECURITY_BUILTIN_DOMAIN_RID, /*BUILTIN\ */
-                               DOMAIN_ALIAS_RID_ADMINS, /*\Administrators */
-                               0, 0, 0, 0, 0, 0, /* No other */
-                               &admin_SID))
-    {
-      PRINTLASTERROR ("Failed to allocate admin sid.");
-      goto done;
-    }
-
-  /* explicit_access[1] grants admins full rights for this object and inherits
-     it to the children */
-  explicit_access[1].grfAccessPermissions = GENERIC_ALL;
-  explicit_access[1].grfAccessMode = SET_ACCESS;
-  explicit_access[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
-  explicit_access[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
-  explicit_access[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
-  explicit_access[1].Trustee.ptstrName = (LPTSTR) admin_SID;
-
-  /* Set up the ACL structure. */
-  if (ERROR_SUCCESS != SetEntriesInAcl(2, explicit_access, NULL, &access_control_list))
-    {
-      PRINTLASTERROR ("Failed to set up Acl.");
-      goto done;
-    }
-
-  /* Initialize a security descriptor */
-  descriptor = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
-               SECURITY_DESCRIPTOR_MIN_LENGTH);
-  if (descriptor == NULL)
-    {
-      PRINTLASTERROR("Failed to allocate descriptor.");
-      goto done;
-    }
-
-  if (!InitializeSecurityDescriptor(descriptor,
-                                    SECURITY_DESCRIPTOR_REVISION))
-    {
-      PRINTLASTERROR("Failed to initialize descriptor.");
-      goto done;
-    }
-
-  /* Now we add the ACL to the the descriptor */
-  if (!SetSecurityDescriptorDacl(descriptor,
-                                 TRUE,     /* bDaclPresent flag */
-                                 access_control_list,
-                                 FALSE))   /* not a default DACL */
-    {
-      PRINTLASTERROR("Failed to set security descriptor.");
-      goto done;
-    }
-
-  /* Finally set up the security attributes structure */
-  security_attributes.nLength = sizeof (SECURITY_ATTRIBUTES);
-  security_attributes.lpSecurityDescriptor = descriptor;
-  security_attributes.bInheritHandle = FALSE;
-
-  /* Use the security attributes to create the directory */
-  if (!CreateDirectoryW(path, &security_attributes))
-    {
-      DWORD err = GetLastError();
-      if (err == ERROR_ALREADY_EXISTS)
-        {
-          /* Verify that the directory has the correct rights */
-          // TODO
-          retval = true;
-          goto done;
-        }
-      ERRORPRINTF ("Failed to create directory. Err: %lu", err);
-    }
-  retval = true;
-
-done:
-
-  if (everyone_SID)
-    FreeSid(everyone_SID);
-  if (admin_SID)
-    FreeSid(admin_SID);
-  if (access_control_list)
-    LocalFree(access_control_list);
-  if (descriptor)
-    LocalFree(descriptor);
-
-  return retval;
-}
-
 /**@brief Writes the selection file containing the instructions
  *
  * If the process is running elevated the instructions are
@@ -894,19 +752,13 @@
 {
   wchar_t *folder_name = NULL,
            *path = NULL;
-  HRESULT result = E_FAIL;
   HANDLE hFile = NULL;
   size_t path_len;
 
-  result = SHGetKnownFolderPath (&FOLDERID_ProgramData, /* Get program data dir */
-                                 KF_FLAG_CREATE | /* Create if it does not exist */
-                                 KF_FLAG_INIT, /* Initialize it if created */
-                                 INVALID_HANDLE_VALUE, /* Get it for the default user */
-                                 &folder_name);
-
-  if (result != S_OK)
+  folder_name = get_program_data_folder();
+  if (!folder_name)
     {
-      PRINTLASTERROR ("Failed to get folder path");
+      ERRORPRINTF("Failed to look up ProgramData folder.\n");
       return NULL;
     }
 
--- a/common/util.c	Fri Aug 29 16:08:50 2014 +0200
+++ b/common/util.c	Fri Aug 29 17:11:35 2014 +0200
@@ -17,6 +17,9 @@
 #include <string.h>
 #else
 #include <windows.h>
+#include <accctrl.h>
+#include <aclapi.h>
+#include <shlobj.h>
 #endif
 
 #ifndef APPNAME
@@ -426,6 +429,46 @@
   return ret;
 }
 
+#ifdef _WIN32
+char *
+get_program_files_folder ()
+{
+  wchar_t *folder_name = NULL;
+  char *retval = NULL;
+  if (SHGetKnownFolderPath (&FOLDERID_ProgramFiles, /* Get program data dir */
+                            KF_FLAG_NO_ALIAS,
+                            INVALID_HANDLE_VALUE, /* Get it for the default user */
+                            &folder_name) != S_OK)
+    {
+      PRINTLASTERROR ("Failed to get program files folder.");
+      return NULL;
+    }
+
+  retval = wchar_to_utf8 (folder_name, wcslen(folder_name));
+  CoTaskMemFree (folder_name);
+  return retval;
+}
+
+/* This is a bit ridicoulous but necessary as shlobj.h contains an inline
+   definition. So only one C file may include it and thus we have to put
+   all our shlobj calls into one file... */
+wchar_t *
+get_program_data_folder ()
+{
+  wchar_t *folder_name = NULL;
+  if (SHGetKnownFolderPath (&FOLDERID_ProgramData, /* Get program data dir */
+                                 KF_FLAG_CREATE | /* Create if it does not exist */
+                                 KF_FLAG_INIT, /* Initialize it if created */
+                                 INVALID_HANDLE_VALUE, /* Get it for the default user */
+                                 &folder_name) != S_OK)
+    {
+      PRINTLASTERROR ("Failed to get folder path");
+      return NULL;
+    }
+  return folder_name;
+}
+#endif
+
 bool
 is_admin()
 {
@@ -556,3 +599,128 @@
 #endif
 }
 
+#ifdef WIN32
+bool
+create_restricted_directory (LPWSTR path)
+{
+  bool retval = false;
+  PSID everyone_SID = NULL,
+       admin_SID = NULL;
+  PACL access_control_list = NULL;
+  PSECURITY_DESCRIPTOR descriptor = NULL;
+  EXPLICIT_ACCESS explicit_access[2];
+  SID_IDENTIFIER_AUTHORITY world_identifier = {SECURITY_WORLD_SID_AUTHORITY},
+                           admin_identifier = {SECURITY_NT_AUTHORITY};
+  SECURITY_ATTRIBUTES security_attributes;
+
+  ZeroMemory(&security_attributes, sizeof(security_attributes));
+  ZeroMemory(&explicit_access, 2 * sizeof(EXPLICIT_ACCESS));
+
+  /* Create a well-known SID for the Everyone group. */
+  if(!AllocateAndInitializeSid(&world_identifier, /* top-level identifier */
+                               1, /* subauthorties count */
+                               SECURITY_WORLD_RID, /* Only one authority */
+                               0, 0, 0, 0, 0, 0, 0, /* No other authorities*/
+                               &everyone_SID))
+    {
+      PRINTLASTERROR ("Failed to allocate world sid.\n");
+      return false;
+    }
+
+  /* Initialize the first EXPLICIT_ACCESS structure for an ACE.
+     to allow everyone read access */
+  explicit_access[0].grfAccessPermissions = GENERIC_READ; /* Give read access */
+  explicit_access[0].grfAccessMode = SET_ACCESS; /* Overwrite other access for all users */
+  explicit_access[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; /* make it stick */
+  explicit_access[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+  explicit_access[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+  explicit_access[0].Trustee.ptstrName  = (LPTSTR) everyone_SID;
+
+  /* Create the SID for the BUILTIN\Administrators group. */
+  if(!AllocateAndInitializeSid(&admin_identifier,
+                               2,
+                               SECURITY_BUILTIN_DOMAIN_RID, /*BUILTIN\ */
+                               DOMAIN_ALIAS_RID_ADMINS, /*\Administrators */
+                               0, 0, 0, 0, 0, 0, /* No other */
+                               &admin_SID))
+    {
+      PRINTLASTERROR ("Failed to allocate admin sid.");
+      goto done;
+    }
+
+  /* explicit_access[1] grants admins full rights for this object and inherits
+     it to the children */
+  explicit_access[1].grfAccessPermissions = GENERIC_ALL;
+  explicit_access[1].grfAccessMode = SET_ACCESS;
+  explicit_access[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+  explicit_access[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+  explicit_access[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
+  explicit_access[1].Trustee.ptstrName = (LPTSTR) admin_SID;
+
+  /* Set up the ACL structure. */
+  if (ERROR_SUCCESS != SetEntriesInAcl(2, explicit_access, NULL, &access_control_list))
+    {
+      PRINTLASTERROR ("Failed to set up Acl.");
+      goto done;
+    }
+
+  /* Initialize a security descriptor */
+  descriptor = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
+               SECURITY_DESCRIPTOR_MIN_LENGTH);
+  if (descriptor == NULL)
+    {
+      PRINTLASTERROR("Failed to allocate descriptor.");
+      goto done;
+    }
+
+  if (!InitializeSecurityDescriptor(descriptor,
+                                    SECURITY_DESCRIPTOR_REVISION))
+    {
+      PRINTLASTERROR("Failed to initialize descriptor.");
+      goto done;
+    }
+
+  /* Now we add the ACL to the the descriptor */
+  if (!SetSecurityDescriptorDacl(descriptor,
+                                 TRUE,     /* bDaclPresent flag */
+                                 access_control_list,
+                                 FALSE))   /* not a default DACL */
+    {
+      PRINTLASTERROR("Failed to set security descriptor.");
+      goto done;
+    }
+
+  /* Finally set up the security attributes structure */
+  security_attributes.nLength = sizeof (SECURITY_ATTRIBUTES);
+  security_attributes.lpSecurityDescriptor = descriptor;
+  security_attributes.bInheritHandle = FALSE;
+
+  /* Use the security attributes to create the directory */
+  if (!CreateDirectoryW(path, &security_attributes))
+    {
+      DWORD err = GetLastError();
+      if (err == ERROR_ALREADY_EXISTS)
+        {
+          /* Verify that the directory has the correct rights */
+          // TODO
+          retval = true;
+          goto done;
+        }
+      ERRORPRINTF ("Failed to create directory. Err: %lu", err);
+    }
+  retval = true;
+
+done:
+
+  if (everyone_SID)
+    FreeSid(everyone_SID);
+  if (admin_SID)
+    FreeSid(admin_SID);
+  if (access_control_list)
+    LocalFree(access_control_list);
+  if (descriptor)
+    LocalFree(descriptor);
+
+  return retval;
+}
+#endif
--- a/common/util.h	Fri Aug 29 16:08:50 2014 +0200
+++ b/common/util.h	Fri Aug 29 17:11:35 2014 +0200
@@ -100,6 +100,42 @@
  */
 char * read_registry_string (const HKEY root, const wchar_t *key,
                              const wchar_t *name);
+
+/**@brief Get the utf-8 encoded path to the program files folder.
+ *
+ * Uses SHGetKnownFolderPath to look up the ProgramFiles folder.
+ * @returns a newly allocated string containing the value or NULL on
+ * error.
+ */
+char * get_program_files_folder ();
+
+/**@brief Get the path to the program data folder.
+ *
+ * Uses SHGetKnownFolderPath to look up the ProgramData folder.
+ * The return value should be freed with CoTaskMemFree
+ * @returns a reference containing the value or NULL on error.
+ */
+wchar_t * get_program_data_folder ();
+
+/**@brief Create a directory with restricted access rights
+  *
+  * This creates a security attributes structure that restricts
+  * write access to the Administrators group but allows everyone to read files
+  * in that directory.
+  * Basically a very complicated version of mkdir path -m 644
+  *
+  * If the directory exists the permissions of that directory are checked if
+  * they are acceptable and true or false is returned accordingly.
+  *
+  * Code based on msdn example:
+  * http://msdn.microsoft.com/en-us/library/windows/desktop/aa446595%28v=vs.85%29.aspx
+  *
+  * @param[in] path Path of the directory to create
+  *
+  * @returns true on success of if the directory exists, false on error
+  */
+bool create_restricted_directory (LPWSTR path);
+
 #endif
 
 #ifdef __cplusplus

http://wald.intevation.org/projects/trustbridge/