#include <winioctl.h>
#include <aclapi.h>
+#include <sddl.h>
+
+#include <sys/acl.h>
+
+/* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
+ define them by hand if not already defined. */
+#ifndef SDDL_REVISION_1
+#define SDDL_REVISION_1 1
+#endif /* SDDL_REVISION_1 */
#ifdef _MSC_VER
/* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER and the
static BOOL g_b_init_get_native_system_info;
static BOOL g_b_init_get_system_times;
static BOOL g_b_init_create_symbolic_link;
+static BOOL g_b_init_get_security_descriptor_dacl;
+static BOOL g_b_init_convert_sd_to_sddl;
+static BOOL g_b_init_convert_sddl_to_sd;
+static BOOL g_b_init_is_valid_security_descriptor;
+static BOOL g_b_init_set_file_security;
/*
BEGIN: Wrapper functions around OpenProcessToken
#ifdef _UNICODE
const char * const LookupAccountSid_Name = "LookupAccountSidW";
const char * const GetFileSecurity_Name = "GetFileSecurityW";
+const char * const SetFileSecurity_Name = "SetFileSecurityW";
#else
const char * const LookupAccountSid_Name = "LookupAccountSidA";
const char * const GetFileSecurity_Name = "GetFileSecurityA";
+const char * const SetFileSecurity_Name = "SetFileSecurityA";
#endif
typedef BOOL (WINAPI * LookupAccountSid_Proc) (
LPCTSTR lpSystemName,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
LPDWORD lpnLengthNeeded);
+typedef BOOL (WINAPI *SetFileSecurity_Proc) (
+ LPCTSTR lpFileName,
+ SECURITY_INFORMATION SecurityInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor);
typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID *pOwner,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID *pGroup,
LPBOOL lpbGroupDefaulted);
+typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ LPBOOL lpbDaclPresent,
+ PACL *pDacl,
+ LPBOOL lpbDaclDefaulted);
typedef BOOL (WINAPI * IsValidSid_Proc) (
PSID sid);
typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
LPTSTR lpSymlinkFileName,
LPTSTR lpTargetFileName,
DWORD dwFlags);
+typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
+ LPCTSTR StringSecurityDescriptor,
+ DWORD StringSDRevision,
+ PSECURITY_DESCRIPTOR *SecurityDescriptor,
+ PULONG SecurityDescriptorSize);
+typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
+ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ DWORD RequestedStringSDRevision,
+ SECURITY_INFORMATION SecurityInformation,
+ LPTSTR *StringSecurityDescriptor,
+ PULONG StringSecurityDescriptorLen);
+typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
/* ** A utility function ** */
static BOOL
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
+ errno = ENOTSUP;
return FALSE;
}
if (g_b_init_get_file_security == 0)
}
if (s_pfn_Get_File_Security == NULL)
{
+ errno = ENOTSUP;
return FALSE;
}
return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
lpnLengthNeeded));
}
+static BOOL WINAPI
+set_file_security (LPCTSTR lpFileName,
+ SECURITY_INFORMATION SecurityInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor)
+{
+ static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+ if (g_b_init_set_file_security == 0)
+ {
+ g_b_init_set_file_security = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Set_File_Security =
+ (SetFileSecurity_Proc) GetProcAddress (
+ hm_advapi32, SetFileSecurity_Name);
+ }
+ if (s_pfn_Set_File_Security == NULL)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+ return (s_pfn_Set_File_Security (lpFileName, SecurityInformation,
+ pSecurityDescriptor));
+}
+
static BOOL WINAPI
get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
PSID *pOwner,
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
+ errno = ENOTSUP;
return FALSE;
}
if (g_b_init_get_security_descriptor_owner == 0)
}
if (s_pfn_Get_Security_Descriptor_Owner == NULL)
{
+ errno = ENOTSUP;
return FALSE;
}
return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
+ errno = ENOTSUP;
return FALSE;
}
if (g_b_init_get_security_descriptor_group == 0)
}
if (s_pfn_Get_Security_Descriptor_Group == NULL)
{
+ errno = ENOTSUP;
return FALSE;
}
return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
lpbGroupDefaulted));
}
+static BOOL WINAPI
+get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ LPBOOL lpbDaclPresent,
+ PACL *pDacl,
+ LPBOOL lpbDaclDefaulted)
+{
+ static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
+ HMODULE hm_advapi32 = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+ if (g_b_init_get_security_descriptor_dacl == 0)
+ {
+ g_b_init_get_security_descriptor_dacl = 1;
+ hm_advapi32 = LoadLibrary ("Advapi32.dll");
+ s_pfn_Get_Security_Descriptor_Dacl =
+ (GetSecurityDescriptorDacl_Proc) GetProcAddress (
+ hm_advapi32, "GetSecurityDescriptorDacl");
+ }
+ if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+ return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
+ lpbDaclPresent, pDacl,
+ lpbDaclDefaulted));
+}
+
static BOOL WINAPI
is_valid_sid (PSID sid)
{
}
return retval;
}
+
+static BOOL WINAPI
+is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
+{
+ static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
+
+ if (is_windows_9x () == TRUE)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+
+ if (g_b_init_is_valid_security_descriptor == 0)
+ {
+ g_b_init_is_valid_security_descriptor = 1;
+ s_pfn_Is_Valid_Security_Descriptor_Proc =
+ (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+ "IsValidSecurityDescriptor");
+ }
+ if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+
+ return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
+}
+
+static BOOL WINAPI
+convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
+ DWORD RequestedStringSDRevision,
+ SECURITY_INFORMATION SecurityInformation,
+ LPTSTR *StringSecurityDescriptor,
+ PULONG StringSecurityDescriptorLen)
+{
+ static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
+ BOOL retval;
+
+ if (is_windows_9x () == TRUE)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+
+ if (g_b_init_convert_sd_to_sddl == 0)
+ {
+ g_b_init_convert_sd_to_sddl = 1;
+#ifdef _UNICODE
+ s_pfn_Convert_SD_To_SDDL =
+ (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+ "ConvertSecurityDescriptorToStringSecurityDescriptorW");
+#else
+ s_pfn_Convert_SD_To_SDDL =
+ (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+ "ConvertSecurityDescriptorToStringSecurityDescriptorA");
+#endif
+ }
+ if (s_pfn_Convert_SD_To_SDDL == NULL)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+
+ retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
+ RequestedStringSDRevision,
+ SecurityInformation,
+ StringSecurityDescriptor,
+ StringSecurityDescriptorLen);
+
+ return retval;
+}
+
+static BOOL WINAPI
+convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
+ DWORD StringSDRevision,
+ PSECURITY_DESCRIPTOR *SecurityDescriptor,
+ PULONG SecurityDescriptorSize)
+{
+ static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
+ BOOL retval;
+
+ if (is_windows_9x () == TRUE)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+
+ if (g_b_init_convert_sddl_to_sd == 0)
+ {
+ g_b_init_convert_sddl_to_sd = 1;
+#ifdef _UNICODE
+ s_pfn_Convert_SDDL_To_SD =
+ (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+ "ConvertStringSecurityDescriptorToSecurityDescriptorW");
+#else
+ s_pfn_Convert_SDDL_To_SD =
+ (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
+ "ConvertStringSecurityDescriptorToSecurityDescriptorA");
+#endif
+ }
+ if (s_pfn_Convert_SDDL_To_SD == NULL)
+ {
+ errno = ENOTSUP;
+ return FALSE;
+ }
+
+ retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
+ StringSDRevision,
+ SecurityDescriptor,
+ SecurityDescriptorSize);
+
+ return retval;
+}
+
\f
/* Return 1 if P is a valid pointer to an object of size SIZE. Return
return target;
}
+\f
+/* Posix ACL emulation. */
+
+int
+acl_valid (acl_t acl)
+{
+ return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
+}
+
+char *
+acl_to_text (acl_t acl, ssize_t *size)
+{
+ LPTSTR str_acl;
+ SECURITY_INFORMATION flags =
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION;
+ char *retval = NULL;
+ ssize_t local_size;
+ int e = errno;
+
+ errno = 0;
+
+ if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
+ {
+ errno = e;
+ /* We don't want to mix heaps, so we duplicate the string in our
+ heap and free the one allocated by the API. */
+ retval = xstrdup (str_acl);
+ if (size)
+ *size = local_size;
+ LocalFree (str_acl);
+ }
+ else if (errno != ENOTSUP)
+ errno = EINVAL;
+
+ return retval;
+}
+
+acl_t
+acl_from_text (const char *acl_str)
+{
+ PSECURITY_DESCRIPTOR psd, retval = NULL;
+ ULONG sd_size;
+ int e = errno;
+
+ errno = 0;
+
+ if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
+ {
+ errno = e;
+ retval = xmalloc (sd_size);
+ memcpy (retval, psd, sd_size);
+ LocalFree (psd);
+ }
+ else if (errno != ENOTSUP)
+ errno = EINVAL;
+
+ return retval;
+}
+
+int
+acl_free (void *ptr)
+{
+ xfree (ptr);
+ return 0;
+}
+
+acl_t
+acl_get_file (const char *fname, acl_type_t type)
+{
+ PSECURITY_DESCRIPTOR psd = NULL;
+
+ if (type == ACL_TYPE_ACCESS)
+ {
+ DWORD sd_len, err;
+ SECURITY_INFORMATION si =
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION ;
+ int e = errno;
+
+ errno = 0;
+ if (!get_file_security (fname, si, psd, 0, &sd_len)
+ && errno != ENOTSUP)
+ {
+ err = GetLastError ();
+ if (err == ERROR_INSUFFICIENT_BUFFER)
+ {
+ psd = xmalloc (sd_len);
+ if (!get_file_security (fname, si, psd, sd_len, &sd_len))
+ {
+ xfree (psd);
+ errno = EIO;
+ psd = NULL;
+ }
+ }
+ else if (err == ERROR_FILE_NOT_FOUND
+ || err == ERROR_PATH_NOT_FOUND)
+ errno = ENOENT;
+ else
+ errno = EIO;
+ }
+ else if (!errno)
+ errno = e;
+ }
+ else if (type != ACL_TYPE_DEFAULT)
+ errno = EINVAL;
+
+ return psd;
+}
+
+int
+acl_set_file (const char *fname, acl_type_t type, acl_t acl)
+{
+ TOKEN_PRIVILEGES old1, old2;
+ DWORD err;
+ BOOL res;
+ int st = 0, retval = -1;
+ SECURITY_INFORMATION flags = 0;
+ PSID psid;
+ PACL pacl;
+ BOOL dflt;
+ BOOL dacl_present;
+ int e;
+
+ if (acl_valid (acl) != 0
+ || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (type == ACL_TYPE_DEFAULT)
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
+ && psid)
+ flags |= OWNER_SECURITY_INFORMATION;
+ if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
+ && psid)
+ flags |= GROUP_SECURITY_INFORMATION;
+ if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
+ &pacl, &dflt)
+ && dacl_present)
+ flags |= DACL_SECURITY_INFORMATION;
+ if (!flags)
+ return 0;
+
+ /* According to KB-245153, setting the owner will succeed if either:
+ (1) the caller is the user who will be the new owner, and has the
+ SE_TAKE_OWNERSHIP privilege, or
+ (2) the caller has the SE_RESTORE privilege, in which case she can
+ set any valid user or group as the owner
+
+ We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
+ privileges, and disregard any failures in obtaining them. If
+ these privileges cannot be obtained, and do not already exist in
+ the calling thread's security token, this function could fail
+ with EPERM. */
+ if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
+ st++;
+ if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
+ st++;
+
+ e = errno;
+ errno = 0;
+ set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl);
+ err = GetLastError ();
+ if (st >= 2)
+ restore_privilege (&old2);
+ if (st >= 1)
+ restore_privilege (&old1);
+
+ if (errno == ENOTSUP)
+ ;
+ else if (err == ERROR_SUCCESS)
+ {
+ retval = 0;
+ errno = e;
+ }
+ else if (err == ERROR_INVALID_OWNER)
+ errno = EPERM;
+ else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+ errno = ENOENT;
+
+ return retval;
+}
+
+\f
/* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
have a fixed max size for file names, so we don't need the kind of
alloc/malloc/realloc dance the gnulib version does. We also don't
g_b_init_get_native_system_info = 0;
g_b_init_get_system_times = 0;
g_b_init_create_symbolic_link = 0;
+ g_b_init_get_security_descriptor_dacl = 0;
+ g_b_init_convert_sd_to_sddl = 0;
+ g_b_init_convert_sddl_to_sd = 0;
+ g_b_init_is_valid_security_descriptor = 0;
+ g_b_init_set_file_security = 0;
num_of_processors = 0;
/* The following sets a handler for shutdown notifications for
console apps. This actually applies to Emacs in both console and