From: Eli Zaretskii Date: Mon, 17 Dec 2012 19:14:34 +0000 (+0200) Subject: Support Posix ACL APIs on MS-Windows. X-Git-Tag: emacs-24.3.90~173^2~7^2~563 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=66447e07c1aa037730127d6fcdd2658f87f13dc0;p=emacs.git Support Posix ACL APIs on MS-Windows. src/w32.c: Include sddl.h and sys/acl.h. (SDDL_REVISION_1): Define if not already defined. (g_b_init_get_security_descriptor_dacl) (g_b_init_convert_sd_to_sddl, g_b_init_convert_sddl_to_sd) (g_b_init_is_valid_security_descriptor) (g_b_init_set_file_security): New static flags. (globals_of_w32): Initialize them to zero. (SetFileSecurity_Name): New string constant. (SetFileSecurity_Proc, GetSecurityDescriptorDacl_Proc) (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (IsValidSecurityDescriptor_Proc): New typedefs. (get_file_security, get_security_descriptor_owner) (get_security_descriptor_group): Set errno to ENOTSUP. (set_file_security, get_security_descriptor_dacl) (is_valid_security_descriptor, convert_sd_to_sddl) (convert_sddl_to_sd, acl_valid, acl_to_text, acl_from_text) (acl_free, acl_get_file, acl_set_file): New functions. src/fileio.c (Fcopy_file) [WINDOWSNT]: Support copying ACLs. nt/inc/sys/acl.h: New file. nt/inc/ms-w32.h (ENOTSUP): Define if undefined. nt/config.nt (HAVE_POSIX_ACL): Define. doc/lispref/files.texi (File Attributes, Changing Files): Update to include MS-Windows support for ACLs. --- diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 922147844bd..a0bbafb116f 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,8 @@ +2012-12-17 Eli Zaretskii + + * files.texi (File Attributes, Changing Files): Update to include + MS-Windows support for ACLs. + 2012-12-16 Romain Francoise * files.texi (File Attributes): Document ACL support and new diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 93bee961929..5440388fe70 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -1357,13 +1357,14 @@ support, then the return value is @code{(nil nil nil nil)}. If Emacs has been compiled with @dfn{ACL} (access control list) support, you can use the function @code{file-acl} to retrieve a file's ACL entries. The format is platform-specific; on GNU/Linux and BSD, -Emacs uses the POSIX ACL interface. For the function -@code{set-file-acl}, see @ref{Changing Files}. +Emacs uses the POSIX ACL interface, while on MS-Windows Emacs emulates +the POSIX ACL interface with native file security APIs. For the +function @code{set-file-acl}, see @ref{Changing Files}. @defun file-acl filename This function returns the ACL entries of the file @var{filename}. The return value is a string containing the textual representation of -the ACL entries, like the following: +the ACL entries. On Posix hosts, it looks like this: @example @group @@ -1375,6 +1376,12 @@ other::r-- @end group @end example +@cindex security descriptor, file +@cindex SDDL, MS-Windows +On MS-Windows, the return value is a textual description of the file's +@dfn{security descriptor} in @acronym{SDDL}, the @dfn{Security +Descriptor Definition Language}. + If the file does not exist or is inaccessible, or if Emacs was unable to determine the ACL entries, then the return value is @code{nil}. The latter can happen for local files if Emacs was not compiled with ACL @@ -1719,7 +1726,8 @@ SELinux support. This function sets the ACL entries of the file @var{filename} to @var{acl-string}. @xref{File Attributes}, for a brief description of ACLs. The @var{acl-string} argument should be a string containing the -textual representation of the desired ACL entries. +textual representation of the desired ACL entries in the format +appropriate for the ACL interface being used. @end defun @node File Names diff --git a/etc/NEWS b/etc/NEWS index 1c82b760946..263ca3cd48a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -44,8 +44,9 @@ simply disabling Transient Mark mode does the same thing. *** Emacs preserves the ACL entries of files when backing up. +++ *** New functions `file-acl' and `set-file-acl' get and set the ACL -entries of a file. On GNU/Linux the POSIX ACL interface is used via -libacl. +entries of a file. On GNU/Linux, the POSIX ACL interface is used via +libacl. On MS-Windows, the NT Security APIs are used to emulate the +POSIX ACL interfaces. * Editing Changes in Emacs 24.4 diff --git a/nt/ChangeLog b/nt/ChangeLog index bcd15422bdf..114fa826b2b 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -1,3 +1,11 @@ +2012-12-17 Eli Zaretskii + + * inc/sys/acl.h: New file. + + * inc/ms-w32.h (ENOTSUP): Define if undefined. + + * config.nt (HAVE_POSIX_ACL): Define. + 2012-12-15 Eli Zaretskii * inc/ms-w32.h (sys_unlink): Provide prototype. diff --git a/nt/config.nt b/nt/config.nt index db26bf6cbae..aef92a8cccd 100644 --- a/nt/config.nt +++ b/nt/config.nt @@ -725,6 +725,9 @@ along with GNU Emacs. If not, see . */ /* Define to 1 if you have the header file. */ #undef HAVE_PNG_H +/* Define to 1 if you have the POSIX ACL support. */ +#define HAVE_POSIX_ACL 1 + /* Define to 1 if you have the `posix_memalign' function. */ #undef HAVE_POSIX_MEMALIGN diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h index aab30391063..78e1d544cde 100644 --- a/nt/inc/ms-w32.h +++ b/nt/inc/ms-w32.h @@ -293,6 +293,10 @@ extern struct tm *localtime_r (time_t const * restrict, struct tm * restrict); #define NSIG 23 #endif +#ifndef ENOTSUP +#define ENOTSUP ENOSYS +#endif + #ifdef _MSC_VER typedef int sigset_t; typedef int ssize_t; diff --git a/nt/inc/sys/acl.h b/nt/inc/sys/acl.h new file mode 100644 index 00000000000..3133e3bfc09 --- /dev/null +++ b/nt/inc/sys/acl.h @@ -0,0 +1,25 @@ +/* Emulation of Posix ACLs for Windows. */ + +#ifndef ACL_H +#define ACL_H + +#define NOMINMAX 1 /* don't define min and max */ +#include + +typedef PSECURITY_DESCRIPTOR acl_t; +typedef unsigned acl_type_t; + +/* Values of acl_type_t */ +#define ACL_TYPE_ACCESS 0 +#define ACL_TYPE_DEFAULT 1 + +typedef unsigned acl_perm_t; + +extern int acl_valid (acl_t); +extern acl_t acl_get_file (const char *, acl_type_t); +extern int acl_set_file (const char *, acl_type_t, acl_t); +extern char * acl_to_text (acl_t, ssize_t *); +extern acl_t acl_from_text (const char *); +extern int acl_free (void *); + +#endif /* ACL_H */ diff --git a/src/ChangeLog b/src/ChangeLog index d5071c541b4..acfd5c561b7 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,27 @@ +2012-12-17 Eli Zaretskii + + Emulate Posix ACL APIs on MS-Windows. + * w32.c: Include sddl.h and sys/acl.h. + (SDDL_REVISION_1): Define if not already defined. + (g_b_init_get_security_descriptor_dacl) + (g_b_init_convert_sd_to_sddl, g_b_init_convert_sddl_to_sd) + (g_b_init_is_valid_security_descriptor) + (g_b_init_set_file_security): New static flags. + (globals_of_w32): Initialize them to zero. + (SetFileSecurity_Name): New string constant. + (SetFileSecurity_Proc, GetSecurityDescriptorDacl_Proc) + (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) + (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) + (IsValidSecurityDescriptor_Proc): New typedefs. + (get_file_security, get_security_descriptor_owner) + (get_security_descriptor_group): Set errno to ENOTSUP. + (set_file_security, get_security_descriptor_dacl) + (is_valid_security_descriptor, convert_sd_to_sddl) + (convert_sddl_to_sd, acl_valid, acl_to_text, acl_from_text) + (acl_free, acl_get_file, acl_set_file): New functions. + + * fileio.c (Fcopy_file) [WINDOWSNT]: Support copying ACLs. + 2012-12-17 Paul Eggert Don't reraise SIGCHLD, as that can now lose (Bug#13192). diff --git a/src/fileio.c b/src/fileio.c index f1cfe0eb625..26150a7e55b 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -1956,6 +1956,14 @@ entries (depending on how Emacs was built). */) out_st.st_mode = 0; #ifdef WINDOWSNT + if (!NILP (preserve_extended_attributes)) + { +#ifdef HAVE_POSIX_ACL + acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS); + if (acl == NULL && errno != ENOTSUP) + report_file_error ("Getting ACL", Fcons (file, Qnil)); +#endif + } if (!CopyFile (SDATA (encoded_file), SDATA (encoded_newname), FALSE)) @@ -1983,6 +1991,17 @@ entries (depending on how Emacs was built). */) /* Restore original attributes. */ SetFileAttributes (filename, attributes); } +#ifdef HAVE_POSIX_ACL + if (acl != NULL) + { + bool fail = + acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0; + if (fail && errno != ENOTSUP) + report_file_error ("Setting ACL", Fcons (newname, Qnil)); + + acl_free (acl); + } +#endif #else /* not WINDOWSNT */ immediate_quit = 1; ifd = emacs_open (SSDATA (encoded_file), O_RDONLY, 0); diff --git a/src/w32.c b/src/w32.c index 50c81f88c72..8ef07e6b077 100644 --- a/src/w32.c +++ b/src/w32.c @@ -117,6 +117,15 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX { #include #include +#include + +#include + +/* 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 @@ -257,6 +266,11 @@ static BOOL g_b_init_copy_sid; 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 @@ -286,9 +300,11 @@ GetProcessTimes_Proc get_process_times_fn = NULL; #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, @@ -318,6 +334,10 @@ typedef BOOL (WINAPI * GetFileSecurity_Proc) ( 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, @@ -326,6 +346,11 @@ typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) ( 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) ( @@ -376,6 +401,18 @@ typedef BOOLEAN (WINAPI *CreateSymbolicLink_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 @@ -621,6 +658,7 @@ get_file_security (LPCTSTR lpFileName, HMODULE hm_advapi32 = NULL; if (is_windows_9x () == TRUE) { + errno = ENOTSUP; return FALSE; } if (g_b_init_get_file_security == 0) @@ -633,6 +671,7 @@ get_file_security (LPCTSTR lpFileName, } if (s_pfn_Get_File_Security == NULL) { + errno = ENOTSUP; return FALSE; } return (s_pfn_Get_File_Security (lpFileName, RequestedInformation, @@ -640,6 +679,35 @@ get_file_security (LPCTSTR lpFileName, 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, @@ -649,6 +717,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, HMODULE hm_advapi32 = NULL; if (is_windows_9x () == TRUE) { + errno = ENOTSUP; return FALSE; } if (g_b_init_get_security_descriptor_owner == 0) @@ -661,6 +730,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, } if (s_pfn_Get_Security_Descriptor_Owner == NULL) { + errno = ENOTSUP; return FALSE; } return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner, @@ -676,6 +746,7 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor, HMODULE hm_advapi32 = NULL; if (is_windows_9x () == TRUE) { + errno = ENOTSUP; return FALSE; } if (g_b_init_get_security_descriptor_group == 0) @@ -688,12 +759,44 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor, } 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) { @@ -888,6 +991,120 @@ create_symbolic_link (LPTSTR lpSymlinkFilename, } 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; +} + /* Return 1 if P is a valid pointer to an object of size SIZE. Return @@ -4477,6 +4694,199 @@ chase_symlinks (const char *file) return target; } + +/* 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; +} + + /* 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 @@ -6848,6 +7258,11 @@ globals_of_w32 (void) 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