diff common/util.c @ 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 698b6a9bd75e
children 1c1964c27b39 6684e5012b7a
line wrap: on
line diff
--- 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

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