aboutsummaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2016-01-06 18:41:36 +0100
committerCorinna Vinschen <corinna@vinschen.de>2016-03-08 13:56:40 +0100
commit9ddf063921f5202100f8e36bb451ae5ac9f76d37 (patch)
tree11d9f59ac8db1b11c7f261f6ce8e4b47720bf1fa /winsup
parentedd7d93484703b81b5e203a9c7c490f117eb4e42 (diff)
downloadnewlib-9ddf063921f5202100f8e36bb451ae5ac9f76d37.zip
newlib-9ddf063921f5202100f8e36bb451ae5ac9f76d37.tar.gz
newlib-9ddf063921f5202100f8e36bb451ae5ac9f76d37.tar.bz2
Implement POSIX.1e ACL functions
* Makefile.in (DLL_OFILES): Add sec_posixacl.o. (SUBLIBS): Add libacl.a (libacl.a): New rule to create libacl.a. * common.din: Export POSIX ACL functions as well as most libacl.a extensions. * fhandler.h (fhander_base::acl_get): New prototype. (fhander_base::acl_set): Ditto. (fhandler_disk_file::acl_get): Ditto. (fhandler_disk_file::acl_set): Ditto. * include/acl/libacl.h: New file. * include/cygwin/version.h: Bump API minor version. * include/sys/acl.h: Drop including cygwin/acl.h. Accommodate throughout Cygwin. Add POSIX ACL definitions. * sec_acl.cc: Include sec_posixacl.h. Replace ILLEGAL_UID and ILLEGAL_GID with ACL_UNDEFINED_ID where sensible. (__aclcheck): New internal acl check function to be used for Solaris and POSIX ACLs. (aclcheck32): Call __aclcheck. (__aclcalcmask): New function to compute ACL_MASK value. (__aclsort): New internal acl sort function to be used for Solaris and POSIX ACLs. (aclsort32): Call __aclsort. (permtostr): Work directly on provided buffer. (__acltotext): New internal acltotext function to be used for Solaris and POSIX ACLs. (acltotext32): Call __acltotext. (__aclfromtext): New internal aclfromtext function to be used for Solaris and POSIX ACLs. (aclfromtext32): Call __aclfromtext. * sec_posixacl.cc: New file implemeting POSIX ACL functions. * sec_posixacl.h: New internal header. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/Makefile.in6
-rw-r--r--winsup/cygwin/common.din39
-rw-r--r--winsup/cygwin/fhandler.cc2
-rw-r--r--winsup/cygwin/fhandler.h5
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc2
-rw-r--r--winsup/cygwin/fhandler_socket.cc2
-rw-r--r--winsup/cygwin/fhandler_tty.cc2
-rw-r--r--winsup/cygwin/fhandler_virtual.cc2
-rw-r--r--winsup/cygwin/include/acl/libacl.h55
-rw-r--r--winsup/cygwin/include/cygwin/version.h3
-rw-r--r--winsup/cygwin/include/sys/acl.h85
-rw-r--r--winsup/cygwin/sec_acl.cc768
-rw-r--r--winsup/cygwin/sec_helper.cc2
-rw-r--r--winsup/cygwin/sec_posixacl.cc1052
-rw-r--r--winsup/cygwin/sec_posixacl.h68
-rw-r--r--winsup/cygwin/security.cc2
-rw-r--r--winsup/utils/getfacl.c3
-rw-r--r--winsup/utils/setfacl.c3
18 files changed, 1825 insertions, 276 deletions
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 271a5be..fac9b3e 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -267,6 +267,7 @@ DLL_OFILES:= \
sec_acl.o \
sec_auth.o \
sec_helper.o \
+ sec_posixacl.o \
security.o \
select.o \
sem.o \
@@ -443,7 +444,7 @@ endif
API_VER:=$(srcdir)/include/cygwin/version.h
LIB_NAME:=libcygwin.a
-SUBLIBS:=libpthread.a libutil.a ${CURDIR}/libm.a ${CURDIR}/libc.a libdl.a libresolv.a librt.a
+SUBLIBS:=libpthread.a libutil.a ${CURDIR}/libm.a ${CURDIR}/libc.a libdl.a libresolv.a librt.a libacl.a
EXTRALIBS:=libautomode.a libbinmode.a libtextmode.a libtextreadmode.a
INSTOBJS:=automode.o binmode.o textmode.o textreadmode.o
TARGET_LIBS:=$(LIB_NAME) $(CYGWIN_START) $(GMON_START) $(LIBGMON_A) $(SUBLIBS) $(INSTOBJS) $(EXTRALIBS)
@@ -643,6 +644,9 @@ libresolv.a: ${LIB_NAME} minires.o
librt.a: ${LIB_NAME} posix_ipc.o
${speclib} ${@F}
+libacl.a: ${LIB_NAME} sec_posixacl.o
+ ${speclib} ${@F}
+
${EXTRALIBS}: lib%.a: %.o
$(AR) cru $@ $?
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index c39d265..fe714d8 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -117,6 +117,45 @@ accept = cygwin_accept SIGFE
accept4 SIGFE
access SIGFE
acl SIGFE
+acl_add_perm NOSIGFE
+acl_calc_mask SIGFE
+acl_check NOSIGFE
+acl_clear_perms NOSIGFE
+acl_cmp SIGFE
+acl_copy_entry NOSIGFE
+acl_copy_ext NOSIGFE
+acl_copy_int NOSIGFE
+acl_create_entry SIGFE
+acl_delete_def_file SIGFE
+acl_delete_entry NOSIGFE
+acl_delete_perm NOSIGFE
+acl_dup SIGFE
+acl_entries NOSIGFE
+acl_equiv_mode SIGFE
+acl_error NOSIGFE
+acl_extended_fd SIGFE
+acl_extended_file SIGFE
+acl_extended_file_nofollow SIGFE
+acl_free SIGFE
+acl_from_mode NOSIGFE
+acl_from_text SIGFE
+acl_get_entry NOSIGFE
+acl_get_fd SIGFE
+acl_get_file SIGFE
+acl_get_perm NOSIGFE
+acl_get_permset NOSIGFE
+acl_get_qualifier SIGFE
+acl_get_tag_type NOSIGFE
+acl_init SIGFE
+acl_set_fd SIGFE
+acl_set_file SIGFE
+acl_set_permset NOSIGFE
+acl_set_qualifier NOSIGFE
+acl_set_tag_type NOSIGFE
+acl_size NOSIGFE
+acl_to_any_text SIGFE
+acl_to_text SIGFE
+acl_valid NOSIGFE
aclcheck NOSIGFE
aclfrommode SIGFE
aclfrompbits SIGFE
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 7e4d996..33743d4 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -13,7 +13,7 @@ details. */
#include <unistd.h>
#include <stdlib.h>
#include <sys/uio.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include <sys/param.h>
#include "cygerrno.h"
#include "perprocess.h"
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index d94f38d..134fd71 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -56,6 +56,7 @@ typedef struct __DIR DIR;
struct dirent;
struct iovec;
struct acl;
+struct __acl_t;
enum dirent_states
{
@@ -355,6 +356,8 @@ public:
virtual int __reg1 fchmod (mode_t mode);
virtual int __reg2 fchown (uid_t uid, gid_t gid);
virtual int __reg3 facl (int, int, struct acl *);
+ virtual struct __acl_t * __reg2 acl_get (uint32_t);
+ virtual int __reg3 acl_set (struct __acl_t *, uint32_t);
virtual ssize_t __reg3 fgetxattr (const char *, void *, size_t);
virtual int __reg3 fsetxattr (const char *, const void *, size_t, int);
virtual int __reg3 fadvise (off_t, off_t, int);
@@ -1011,6 +1014,8 @@ class fhandler_disk_file: public fhandler_base
int __reg1 fchmod (mode_t mode);
int __reg2 fchown (uid_t uid, gid_t gid);
int __reg3 facl (int, int, struct acl *);
+ struct __acl_t * __reg2 acl_get (uint32_t);
+ int __reg3 acl_set (struct __acl_t *, uint32_t);
ssize_t __reg3 fgetxattr (const char *, void *, size_t);
int __reg3 fsetxattr (const char *, const void *, size_t, int);
int __reg3 fadvise (off_t, off_t, int);
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index 7d729e3..470dae8 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -13,7 +13,7 @@ details. */
#include <winioctl.h>
#include <lm.h>
#include <stdlib.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include <sys/statvfs.h>
#include "cygerrno.h"
#include "security.h"
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 7d3efad..990cdc7 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -41,7 +41,7 @@
#include "wininfo.h"
#include <unistd.h>
#include <sys/param.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include "cygtls.h"
#include <sys/un.h>
#include "ntdll.h"
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index ee37ed4..a39a566 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -12,7 +12,7 @@ details. */
#include "winsup.h"
#include <stdlib.h>
#include <sys/param.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include <cygwin/kd.h>
#include "cygerrno.h"
#include "security.h"
diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc
index 2d56d74..8f302a7 100644
--- a/winsup/cygwin/fhandler_virtual.cc
+++ b/winsup/cygwin/fhandler_virtual.cc
@@ -10,7 +10,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include <sys/statvfs.h>
#include "cygerrno.h"
#include "path.h"
diff --git a/winsup/cygwin/include/acl/libacl.h b/winsup/cygwin/include/acl/libacl.h
new file mode 100644
index 0000000..b93d686
--- /dev/null
+++ b/winsup/cygwin/include/acl/libacl.h
@@ -0,0 +1,55 @@
+/* acl/libacl.h: Non-POSIX extensions of libacl
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _ACL_LIBACL_H
+#define _ACL_LIBACL_H
+
+#include <sys/acl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Sync'd with cygwin/acl.h values. */
+#define ACL_MULTI_ERROR (0x4)
+#define ACL_DUPLICATE_ERROR (0x5)
+#define ACL_ENTRY_ERROR (0x6)
+#define ACL_MISS_ERROR (0x7)
+
+/* acl_to_any_text options. */
+#define TEXT_ABBREVIATE (0x01)
+#define TEXT_NUMERIC_IDS (0x02)
+#define TEXT_SOME_EFFECTIVE (0x04)
+#define TEXT_ALL_EFFECTIVE (0x08)
+#define TEXT_SMART_INDENT (0x10)
+
+extern int acl_check (acl_t __acl, int *__last);
+extern int acl_cmp (acl_t __acl1, acl_t __acl2);
+extern int acl_entries (acl_t __acl);
+extern int acl_equiv_mode (acl_t __acl, mode_t *__mode_p);
+extern const char *acl_error (int __code);
+extern int acl_extended_fd (int __fd);
+extern int acl_extended_file (const char *__path_p);
+extern int acl_extended_file_nofollow (const char *__path_p);
+extern acl_t acl_from_mode (mode_t __mode);
+extern int acl_get_perm (acl_permset_t __permset_d, acl_perm_t __perm);
+extern char *acl_to_any_text (acl_t __acl, const char *__prefix,
+ char __separator, int __options);
+
+#if 0
+/* TODO */
+struct error_context;
+extern int perm_copy_file (const char *, const char *, struct error_context *);
+extern int perm_copy_fd (const char *, int, const char *, int,
+ struct error_context *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _ACL_LIBACL_H */
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index be85ce1..4edb8db 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -476,13 +476,14 @@ details. */
292: Export rpmatch.
293: Convert utmpname/utmpxname to int.
294: Export clog10, clog10f.
+ 295: Export POSIX ACL functions.
*/
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull,
sigaltstack, sethostname. */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 294
+#define CYGWIN_VERSION_API_MINOR 295
/* There is also a compatibity version number associated with the
shared memory regions. It is incremented when incompatible
diff --git a/winsup/cygwin/include/sys/acl.h b/winsup/cygwin/include/sys/acl.h
index 89c38bc..c3a9fc1 100644
--- a/winsup/cygwin/include/sys/acl.h
+++ b/winsup/cygwin/include/sys/acl.h
@@ -12,6 +12,89 @@ details. */
#ifndef _SYS_ACL_H
#define _SYS_ACL_H
-#include <cygwin/acl.h>
+#include <_ansi.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* POSIX ACL types and functions. The implementation is based on the
+ internal original Solaris implementation as defined in cygwin/acl.h.
+ However, we don't include cygwin/acl.h from here to avoid poisoning
+ the namespace. */
+
+/* acl_perm_t constants */
+#define ACL_READ (0x4)
+#define ACL_WRITE (0x2)
+#define ACL_EXECUTE (0x1)
+
+/* acl_tag_t constants, in sync with values from cygwin/acl.h */
+#define ACL_UNDEFINED_TAG (0x0000)
+#define ACL_USER_OBJ (0x0001)
+#define ACL_USER (0x0002)
+#define ACL_GROUP_OBJ (0x0004)
+#define ACL_GROUP (0x0008)
+#define ACL_MASK (0x0010)
+#define ACL_OTHER (0x0020)
+
+/* acl_type_t constants */
+#define ACL_TYPE_ACCESS (0x0)
+#define ACL_TYPE_DEFAULT (0x1)
+
+/* qualifier constant */
+#define ACL_UNDEFINED_ID ((id_t) -1)
+
+/* entry_id constants */
+#define ACL_FIRST_ENTRY (0x0)
+#define ACL_NEXT_ENTRY (0x1)
+
+/* types */
+typedef uint32_t acl_perm_t, acl_type_t, acl_tag_t;
+typedef uint64_t acl_permset_t;
+typedef uint64_t acl_entry_t;
+
+struct __acl_t;
+typedef struct __acl_t *acl_t;
+
+extern int acl_add_perm (acl_permset_t __permset_d, acl_perm_t __perm);
+extern int acl_calc_mask (acl_t *__acl_p);
+extern int acl_clear_perms (acl_permset_t __permset_d);
+extern int acl_copy_entry (acl_entry_t __dest_d, acl_entry_t __src_d);
+extern ssize_t acl_copy_ext (void *__buf_p, acl_t __acl, ssize_t __size);
+extern acl_t acl_copy_int (const void *__buf_p);
+extern int acl_create_entry (acl_t *__acl_p, acl_entry_t *__entry_p);
+extern int acl_delete_def_file (const char *__path_p);
+extern int acl_delete_entry (acl_t __acl, acl_entry_t __entry_d);
+extern int acl_delete_perm (acl_permset_t __permset_d, acl_perm_t __perm);
+extern acl_t acl_dup (acl_t __acl);
+extern int acl_free (void *__obj_p);
+extern acl_t acl_from_text (const char *__buf_p);
+extern int acl_get_entry (acl_t __acl, int __entry_id,
+ acl_entry_t *__entry_p);
+extern acl_t acl_get_fd (int __fd);
+extern acl_t acl_get_file (const char *__path_p, acl_type_t __type);
+extern int acl_get_permset (acl_entry_t __entry_d,
+ acl_permset_t *__permset_p);
+extern void *acl_get_qualifier (acl_entry_t __entry_d);
+extern int acl_get_tag_type (acl_entry_t __entry_d,
+ acl_tag_t *__tag_type_p);
+extern acl_t acl_init (int __count);
+extern int acl_set_fd (int __fd, acl_t __acl);
+extern int acl_set_file (const char *__path_p, acl_type_t __type,
+ acl_t __acl);
+extern int acl_set_permset (acl_entry_t __entry_d,
+ acl_permset_t __permset_d);
+extern int acl_set_qualifier (acl_entry_t __entry_d,
+ const void *__tag_qualifier_p);
+extern int acl_set_tag_type (acl_entry_t __entry_d, acl_tag_t __tag_type);
+extern ssize_t acl_size (acl_t __acl);
+extern char *acl_to_text (acl_t __acl, ssize_t *__len_p);
+extern int acl_valid (acl_t __acl);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* _SYS_ACL_H */
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index de40717..052856f 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -13,7 +13,6 @@ details. */
#include "winsup.h"
#include <stdlib.h>
-#include <sys/acl.h>
#include <ctype.h>
#include "cygerrno.h"
#include "security.h"
@@ -23,6 +22,7 @@ details. */
#include "cygheap.h"
#include "ntdll.h"
#include "tls_pbuf.h"
+#include "sec_posixacl.h"
/* How does a correctly constructed new-style Windows ACL claiming to be a
POSIX ACL look like?
@@ -118,7 +118,8 @@ searchace (aclent_t *aclp, int nentries, int type, uid_t id)
int i;
for (i = 0; i < nentries; ++i)
- if ((aclp[i].a_type == type && (id == ILLEGAL_UID || aclp[i].a_id == id))
+ if ((aclp[i].a_type == type
+ && (id == ACL_UNDEFINED_ID || aclp[i].a_id == id))
|| !aclp[i].a_type)
return i;
return -1;
@@ -186,25 +187,25 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
{
aclbufp = (aclent_t *) tp.c_get ();
aclbufp[0].a_type = USER_OBJ;
- aclbufp[0].a_id = ILLEGAL_UID;
+ aclbufp[0].a_id = ACL_UNDEFINED_ID;
aclbufp[0].a_perm = (attr >> 6) & S_IRWXO;
aclbufp[1].a_type = GROUP_OBJ;
- aclbufp[1].a_id = ILLEGAL_GID;
+ aclbufp[1].a_id = ACL_UNDEFINED_ID;
aclbufp[1].a_perm = (attr >> 3) & S_IRWXO;
aclbufp[2].a_type = OTHER_OBJ;
- aclbufp[2].a_id = ILLEGAL_GID;
+ aclbufp[2].a_id = ACL_UNDEFINED_ID;
aclbufp[2].a_perm = attr & S_IRWXO;
nentries = MIN_ACL_ENTRIES;
if (S_ISDIR (attr))
{
aclbufp[3].a_type = DEF_USER_OBJ;
- aclbufp[3].a_id = ILLEGAL_UID;
+ aclbufp[3].a_id = ACL_UNDEFINED_ID;
aclbufp[3].a_perm = (attr >> 6) & S_IRWXO;
aclbufp[4].a_type = GROUP_OBJ;
- aclbufp[4].a_id = ILLEGAL_GID;
+ aclbufp[4].a_id = ACL_UNDEFINED_ID;
aclbufp[4].a_perm = (attr >> 3) & S_IRWXO;
aclbufp[5].a_type = OTHER_OBJ;
- aclbufp[5].a_id = ILLEGAL_GID;
+ aclbufp[5].a_id = ACL_UNDEFINED_ID;
aclbufp[5].a_perm = attr & S_IRWXO;
nentries += MIN_ACL_ENTRIES;
}
@@ -618,19 +619,19 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
if (attr_ret)
*attr_ret &= S_IFMT;
if (uid_ret)
- *uid_ret = ILLEGAL_UID;
+ *uid_ret = ACL_UNDEFINED_ID;
if (gid_ret)
- *gid_ret = ILLEGAL_GID;
+ *gid_ret = ACL_UNDEFINED_ID;
if (aclbufp)
{
aclbufp[0].a_type = USER_OBJ;
- aclbufp[0].a_id = ILLEGAL_UID;
+ aclbufp[0].a_id = ACL_UNDEFINED_ID;
aclbufp[0].a_perm = 0;
aclbufp[1].a_type = GROUP_OBJ;
- aclbufp[1].a_id = ILLEGAL_GID;
+ aclbufp[1].a_id = ACL_UNDEFINED_ID;
aclbufp[1].a_perm = 0;
aclbufp[2].a_type = OTHER_OBJ;
- aclbufp[2].a_id = ILLEGAL_GID;
+ aclbufp[2].a_id = ACL_UNDEFINED_ID;
aclbufp[2].a_perm = 0;
return MIN_ACL_ENTRIES;
}
@@ -674,7 +675,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
lacl[1].a_type = GROUP_OBJ;
lacl[1].a_id = gid;
lacl[2].a_type = OTHER_OBJ;
- lacl[2].a_id = ILLEGAL_GID;
+ lacl[2].a_id = ACL_UNDEFINED_ID;
/* Create array to collect SIDs of all entries in lacl. */
aclsid = (cygpsid *) tp.w_get ();
aclsid[0] = owner_sid;
@@ -730,7 +731,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
>= 0)
{
lacl[pos].a_type = CLASS_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_id = ACL_UNDEFINED_ID;
lacl[pos].a_perm = CYG_ACE_MASK_TO_POSIX (ace->Mask);
aclsid[pos] = well_known_null_sid;
}
@@ -743,7 +744,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
DEF_CLASS_OBJ)) >= 0)
{
lacl[pos].a_type = DEF_CLASS_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_id = ACL_UNDEFINED_ID;
lacl[pos].a_perm = CYG_ACE_MASK_TO_POSIX (ace->Mask);
aclsid[pos] = well_known_null_sid;
}
@@ -767,7 +768,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
else if (ace_sid == well_known_world_sid)
{
type = OTHER_OBJ;
- id = ILLEGAL_GID;
+ id = ACL_UNDEFINED_ID;
if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE
&& !(ace->Header.AceFlags & INHERIT_ONLY))
saw_other_obj = true;
@@ -776,14 +777,14 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
{
type = DEF_USER_OBJ;
types_def |= type;
- id = ILLEGAL_GID;
+ id = ACL_UNDEFINED_ID;
saw_def_user_obj = true;
}
else if (ace_sid == well_known_creator_group_sid)
{
type = DEF_GROUP_OBJ;
types_def |= type;
- id = ILLEGAL_GID;
+ id = ACL_UNDEFINED_ID;
saw_def_group_obj = true;
}
else
@@ -888,10 +889,10 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
{
if (owner_eq_group && !saw_def_group_obj && attr & S_ISGID)
{
- /* This needs post-processing in the following GROUP_OBJ
- handling... Set id to ILLEGAL_GID to play it safe. */
+ /* Needs post-processing in the following GROUP_OBJ block.
+ Set id to ACL_UNDEFINED_ID to play it safe. */
type = GROUP_OBJ;
- id = ILLEGAL_GID;
+ id = ACL_UNDEFINED_ID;
}
else
type = USER;
@@ -944,7 +945,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
&& (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
{
lacl[pos].a_type = CLASS_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_id = ACL_UNDEFINED_ID;
class_perm |= lacl[1].a_perm;
lacl[pos].a_perm = class_perm;
aclsid[pos] = well_known_null_sid;
@@ -960,7 +961,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
&& (pos = searchace (lacl, MAX_ACL_ENTRIES, CLASS_OBJ)) >= 0)
{
lacl[pos].a_type = CLASS_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_id = ACL_UNDEFINED_ID;
lacl[pos].a_perm = lacl[1].a_perm; /* == group perms */
aclsid[pos] = well_known_null_sid;
}
@@ -1004,7 +1005,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
if (!(types_def & OTHER_OBJ) && pos < MAX_ACL_ENTRIES)
{
lacl[pos].a_type = DEF_OTHER_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_id = ACL_UNDEFINED_ID;
lacl[pos].a_perm = lacl[2].a_perm;
aclsid[pos] = well_known_world_sid;
pos++;
@@ -1019,7 +1020,7 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
&& (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
{
lacl[pos].a_type = DEF_CLASS_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_id = ACL_UNDEFINED_ID;
lacl[pos].a_perm = def_class_perm;
if (def_pgrp_pos >= 0)
lacl[pos].a_perm |= lacl[def_pgrp_pos].a_perm;
@@ -1175,130 +1176,151 @@ facl32 (int fd, int cmd, int nentries, aclent_t *aclbufp)
return res;
}
-extern "C" int
-aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
+int
+__aclcheck (aclent_t *aclbufp, int nentries, int *which, bool posix)
{
bool has_user_obj = false;
bool has_group_obj = false;
bool has_other_obj = false;
bool has_class_obj = false;
- bool has_ug_objs __attribute__ ((unused)) = false;
- bool has_def_objs __attribute__ ((unused)) = false;
- bool has_def_user_obj __attribute__ ((unused)) = false;
+ bool has_ug_objs = false;
+ bool has_def_objs = false;
+ bool has_def_user_obj = false;
bool has_def_group_obj = false;
bool has_def_other_obj = false;
bool has_def_class_obj = false;
- bool has_def_ug_objs __attribute__ ((unused)) = false;
+ bool has_def_ug_objs = false;
int pos2;
for (int pos = 0; pos < nentries; ++pos)
- switch (aclbufp[pos].a_type)
- {
- case USER_OBJ:
- if (has_user_obj)
- {
- if (which)
- *which = pos;
- return USER_ERROR;
- }
- has_user_obj = true;
- break;
- case GROUP_OBJ:
- if (has_group_obj)
- {
- if (which)
- *which = pos;
- return GRP_ERROR;
- }
- has_group_obj = true;
- break;
- case OTHER_OBJ:
- if (has_other_obj)
- {
- if (which)
- *which = pos;
- return OTHER_ERROR;
- }
- has_other_obj = true;
- break;
- case CLASS_OBJ:
- if (has_class_obj)
- {
- if (which)
- *which = pos;
- return CLASS_ERROR;
- }
- has_class_obj = true;
- break;
- case USER:
- case GROUP:
- if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
- aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
- {
- if (which)
- *which = pos2;
- return DUPLICATE_ERROR;
- }
- has_ug_objs = true;
- break;
- case DEF_USER_OBJ:
- if (has_def_user_obj)
- {
- if (which)
- *which = pos;
- return USER_ERROR;
- }
- has_def_objs = has_def_user_obj = true;
- break;
- case DEF_GROUP_OBJ:
- if (has_def_group_obj)
- {
- if (which)
- *which = pos;
- return GRP_ERROR;
- }
- has_def_objs = has_def_group_obj = true;
- break;
- case DEF_OTHER_OBJ:
- if (has_def_other_obj)
- {
- if (which)
- *which = pos;
- return OTHER_ERROR;
- }
- has_def_objs = has_def_other_obj = true;
- break;
- case DEF_CLASS_OBJ:
- if (has_def_class_obj)
- {
- if (which)
- *which = pos;
- return CLASS_ERROR;
- }
- has_def_objs = has_def_class_obj = true;
- break;
- case DEF_USER:
- case DEF_GROUP:
- if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
- aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
- {
- if (which)
- *which = pos2;
- return DUPLICATE_ERROR;
- }
- has_def_objs = has_def_ug_objs = true;
- break;
- default:
- return ENTRY_ERROR;
- }
+ {
+ /* POSIX ACLs may contain deleted entries. Just ignore them. */
+ if (posix && aclbufp[pos].a_type == ACL_DELETED_TAG)
+ continue;
+ /* POSIX defines two sorts of ACLs, access and default, none of which
+ is supposed to have the ACL_DEFAULT flag set. */
+ if (posix && (aclbufp[pos].a_type & ACL_DEFAULT))
+ {
+ if (which)
+ *which = pos;
+ return ENTRY_ERROR;
+ }
+ switch (aclbufp[pos].a_type)
+ {
+ case USER_OBJ:
+ if (has_user_obj)
+ {
+ if (which)
+ *which = pos;
+ return USER_ERROR;
+ }
+ has_user_obj = true;
+ break;
+ case GROUP_OBJ:
+ if (has_group_obj)
+ {
+ if (which)
+ *which = pos;
+ return GRP_ERROR;
+ }
+ has_group_obj = true;
+ break;
+ case OTHER_OBJ:
+ if (has_other_obj)
+ {
+ if (which)
+ *which = pos;
+ return OTHER_ERROR;
+ }
+ has_other_obj = true;
+ break;
+ case CLASS_OBJ:
+ if (has_class_obj)
+ {
+ if (which)
+ *which = pos;
+ return CLASS_ERROR;
+ }
+ has_class_obj = true;
+ break;
+ case USER:
+ case GROUP:
+ if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
+ aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
+ {
+ if (which)
+ *which = pos2;
+ return DUPLICATE_ERROR;
+ }
+ has_ug_objs = true;
+ break;
+ case DEF_USER_OBJ:
+ if (has_def_user_obj)
+ {
+ if (which)
+ *which = pos;
+ return USER_ERROR;
+ }
+ has_def_objs = has_def_user_obj = true;
+ break;
+ case DEF_GROUP_OBJ:
+ if (has_def_group_obj)
+ {
+ if (which)
+ *which = pos;
+ return GRP_ERROR;
+ }
+ has_def_objs = has_def_group_obj = true;
+ break;
+ case DEF_OTHER_OBJ:
+ if (has_def_other_obj)
+ {
+ if (which)
+ *which = pos;
+ return OTHER_ERROR;
+ }
+ has_def_objs = has_def_other_obj = true;
+ break;
+ case DEF_CLASS_OBJ:
+ if (has_def_class_obj)
+ {
+ if (which)
+ *which = pos;
+ return CLASS_ERROR;
+ }
+ has_def_objs = has_def_class_obj = true;
+ break;
+ case DEF_USER:
+ case DEF_GROUP:
+ if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
+ aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
+ {
+ if (which)
+ *which = pos2;
+ return DUPLICATE_ERROR;
+ }
+ has_def_objs = has_def_ug_objs = true;
+ break;
+ default:
+ if (which)
+ *which = pos;
+ return ENTRY_ERROR;
+ }
+ }
if (!has_user_obj
|| !has_group_obj
|| !has_other_obj
- || (has_def_objs
- && (!has_def_user_obj || !has_def_group_obj || !has_def_other_obj))
- || (has_ug_objs && !has_class_obj)
- || (has_def_ug_objs && !has_def_class_obj)
- )
+ || (has_ug_objs && !has_class_obj))
+ {
+ if (which)
+ *which = -1;
+ return MISS_ERROR;
+ }
+ /* Check for missing default entries only on Solaris ACLs. */
+ if (!posix &&
+ ((has_def_objs
+ && !(has_def_user_obj && has_def_group_obj && has_def_other_obj))
+ || (has_def_ug_objs && !has_def_class_obj)))
{
if (which)
*which = -1;
@@ -1307,22 +1329,44 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
return 0;
}
-void
+extern "C" int
+aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
+{
+ return __aclcheck (aclbufp, nentries, which, false);
+}
+
+/* For the sake of acl_calc_mask, return -1 if the ACL doesn't need a mask
+ or if a mask entry already exists (__aclcalcmask sets the mask by itself).
+ Otherwise return the mask value so acl_calc_mask can create a mask entry.
+ This doesn't matter when called from aclsort. */
+mode_t
__aclcalcmask (aclent_t *aclbufp, int nentries)
{
mode_t mask = 0;
+ bool need_mask = false;
int mask_idx = -1;
for (int idx = 0; idx < nentries; ++idx)
- {
- if (aclbufp[idx].a_type == CLASS_OBJ)
- mask_idx = idx;
- else if (aclbufp[idx].a_type
- & (USER | GROUP_OBJ | GROUP))
+ switch (aclbufp[idx].a_type)
+ {
+ case USER:
+ case GROUP:
+ need_mask = true;
+ /*FALLTHRU*/
+ case GROUP_OBJ:
mask |= aclbufp[idx].a_perm;
- }
+ break;
+ case CLASS_OBJ:
+ mask_idx = idx;
+ break;
+ default:
+ break;
+ }
if (mask_idx != -1)
aclbufp[mask_idx].a_perm = mask;
+ if (need_mask && mask_idx == -1)
+ return mask;
+ return (acl_perm_t) -1;
}
static int
@@ -1336,15 +1380,25 @@ acecmp (const void *a1, const void *a2)
#undef ace
}
-extern "C" int
-aclsort32 (int nentries, int calclass, aclent_t *aclbufp)
+/* Sorts any acl. Called from sec_posixacl.cc. */
+int
+__aclsort (int nentries, aclent_t *aclbufp)
{
- if (aclcheck32 (aclbufp, nentries, NULL))
+ if (!aclbufp || nentries < 0)
{
set_errno (EINVAL);
return -1;
}
- if (!aclbufp || nentries < 1)
+ if (nentries > 0)
+ qsort ((void *) aclbufp, nentries, sizeof (aclent_t), acecmp);
+ return 0;
+}
+
+extern "C" int
+aclsort32 (int nentries, int calclass, aclent_t *aclbufp)
+{
+ if (!aclbufp || nentries < MIN_ACL_ENTRIES
+ || aclcheck32 (aclbufp, nentries, NULL))
{
set_errno (EINVAL);
return -1;
@@ -1444,79 +1498,224 @@ aclfrompbits32 (aclent_t *aclbufp, int nentries, mode_t *pbitsp)
}
static char *
-permtostr (mode_t perm)
+permtostr (char *bufp, mode_t perm)
{
- static char pbuf[4];
-
- pbuf[0] = (perm & S_IROTH) ? 'r' : '-';
- pbuf[1] = (perm & S_IWOTH) ? 'w' : '-';
- pbuf[2] = (perm & S_IXOTH) ? 'x' : '-';
- pbuf[3] = '\0';
- return pbuf;
+ *bufp++ = (perm & S_IROTH) ? 'r' : '-';
+ *bufp++ = (perm & S_IWOTH) ? 'w' : '-';
+ *bufp++ = (perm & S_IXOTH) ? 'x' : '-';
+ return bufp;
}
-extern "C" char *
-acltotext32 (aclent_t *aclbufp, int aclcnt)
+#define _OPT(o) (options & (o))
+
+#define _CHK(l) \
+ if (bufp + (l) >= buf + 2 * NT_MAX_PATH - 1) \
+ { \
+ set_errno (ENOMEM); \
+ return NULL; \
+ }
+#define _CPY(s) ({ \
+ const char *_s = (s); \
+ _CHK (strlen (_s)); \
+ bufp = stpcpy (bufp, _s); \
+ })
+#define _PTS(p) { \
+ _CHK (3); \
+ bufp = permtostr (bufp, p); \
+ }
+
+#define _CMP(s) (!strncmp (bufp, acl_part[s].str, acl_part[s].len))
+
+struct _acl_part
+{
+ const char *str;
+ size_t len;
+};
+
+static _acl_part acl_part_l[] =
+{
+ { "default:", 8 },
+ { "user:", 5 },
+ { "group:", 6 },
+ { "mask:", 5 },
+ { "other:", 6 }
+};
+
+static _acl_part acl_part_s[] =
+{
+ { "d:", 2 },
+ { "u:", 2 },
+ { "g:", 2 },
+ { "m:", 2 },
+ { "o:", 2 }
+};
+
+enum _acl_type {
+ default_s,
+ user_s,
+ group_s,
+ mask_s,
+ other_s,
+ none_s
+};
+
+char *
+__acltotext (aclent_t *aclbufp, int aclcnt, const char *prefix, char separator,
+ int options)
{
if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES
- || aclcheck32 (aclbufp, aclcnt, NULL))
+ || aclsort32 (aclcnt, 0, aclbufp))
{
set_errno (EINVAL);
return NULL;
}
+ cyg_ldap cldap;
tmp_pathbuf tp;
- char *buf = tp.c_get ();
- buf[0] = '\0';
+ char *buf = tp.t_get ();
+ char *bufp = buf;
+ char *entry_start;
bool first = true;
+ struct passwd *pw;
+ struct group *gr;
+ mode_t mask = S_IRWXO;
+ mode_t def_mask = S_IRWXO;
+ mode_t effective;
+ int pos;
+ _acl_part *acl_part = _OPT (TEXT_ABBREVIATE) ? acl_part_s : acl_part_l;
- for (int pos = 0; pos < aclcnt; ++pos)
+ *bufp = '\0';
+ /* If effective rights are requested, fetch mask values. */
+ if (_OPT (TEXT_SOME_EFFECTIVE | TEXT_ALL_EFFECTIVE))
+ {
+ if ((pos = searchace (aclbufp, aclcnt, CLASS_OBJ)) >= 0)
+ mask = aclbufp[pos].a_perm;
+ if ((pos = searchace (aclbufp, aclcnt, DEF_CLASS_OBJ)) >= 0)
+ def_mask = aclbufp[pos].a_perm;
+ }
+ for (pos = 0; pos < aclcnt; ++pos)
{
if (!first)
- strcat (buf, ",");
+ {
+ _CHK (1);
+ *bufp++ = separator;
+ }
first = false;
- if (aclbufp[pos].a_type & ACL_DEFAULT)
- strcat (buf, "default");
+ /* Rememeber start position of entry to compute TEXT_SMART_INDENT tabs. */
+ entry_start = bufp;
+ /* prefix */
+ if (prefix)
+ _CPY (prefix);
+ /* Solaris default acl? */
+ if (!_OPT (TEXT_IS_POSIX) && aclbufp[pos].a_type & ACL_DEFAULT)
+ _CPY (acl_part[default_s].str);
+ /* acl type */
switch (aclbufp[pos].a_type & ~ACL_DEFAULT)
{
case USER_OBJ:
- __small_sprintf (buf + strlen (buf), "user::%s",
- permtostr (aclbufp[pos].a_perm));
- break;
case USER:
- __small_sprintf (buf + strlen (buf), "user:%d:%s",
- aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
+ _CPY (acl_part[user_s].str);
break;
case GROUP_OBJ:
- __small_sprintf (buf + strlen (buf), "group::%s",
- permtostr (aclbufp[pos].a_perm));
- break;
case GROUP:
- __small_sprintf (buf + strlen (buf), "group:%d:%s",
- aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
+ _CPY (acl_part[group_s].str);
break;
case CLASS_OBJ:
- __small_sprintf (buf + strlen (buf), "mask::%s",
- permtostr (aclbufp[pos].a_perm));
+ _CPY (acl_part[mask_s].str);
break;
case OTHER_OBJ:
- __small_sprintf (buf + strlen (buf), "other::%s",
- permtostr (aclbufp[pos].a_perm));
+ _CPY (acl_part[other_s].str);
+ break;
+ }
+ /* id, if any */
+ switch (aclbufp[pos].a_type & ~ACL_DEFAULT)
+ {
+ case USER:
+ if (_OPT (TEXT_NUMERIC_IDS)
+ || !(pw = internal_getpwuid (aclbufp[pos].a_id, &cldap)))
+ {
+ _CHK (11);
+ bufp += __small_sprintf (bufp, "%u:", aclbufp[pos].a_id);
+ }
+ else
+ {
+ _CHK (strlen (pw->pw_name + 1));
+ bufp += __small_sprintf (bufp, "%s:", pw->pw_name);
+ }
+ break;
+ case GROUP:
+ if (_OPT (TEXT_NUMERIC_IDS)
+ || !(gr = internal_getgrgid (aclbufp[pos].a_id, &cldap)))
+ {
+ _CHK (11);
+ bufp += __small_sprintf (bufp, "%u:", aclbufp[pos].a_id);
+ }
+ else
+ {
+ _CHK (strlen (gr->gr_name));
+ bufp += __small_sprintf (bufp, "%s:", gr->gr_name);
+ }
break;
default:
- set_errno (EINVAL);
- return NULL;
+ _CPY (":");
+ break;
}
+ /* real permissions */
+ _PTS (aclbufp[pos].a_perm);
+ if (!_OPT (TEXT_SOME_EFFECTIVE | TEXT_ALL_EFFECTIVE))
+ continue;
+ /* effective permissions */
+ switch (aclbufp[pos].a_type)
+ {
+ case USER:
+ case GROUP_OBJ:
+ case GROUP:
+ effective = aclbufp[pos].a_perm & mask;
+ break;
+ case DEF_USER:
+ case DEF_GROUP_OBJ:
+ case DEF_GROUP:
+ effective = aclbufp[pos].a_perm & def_mask;
+ break;
+ default:
+ continue;
+ }
+ if (_OPT (TEXT_ALL_EFFECTIVE) || effective != aclbufp[pos].a_perm)
+ {
+ if (_OPT (TEXT_SMART_INDENT))
+ {
+ int tabs = 3 - (bufp - entry_start) / 8;
+ if (tabs-- > 0)
+ {
+ _CHK (tabs);
+ while (tabs-- > 0)
+ *bufp++ = '\t';
+ }
+ }
+ _CPY ("\t#effective:");
+ _PTS (effective);
+ }
+ }
+ if (_OPT (TEXT_END_SEPARATOR))
+ {
+ _CHK (1);
+ *bufp++ = separator;
+ *bufp++ = '\0';
}
return strdup (buf);
}
+extern "C" char *
+acltotext32 (aclent_t *aclbufp, int aclcnt)
+{
+ return __acltotext (aclbufp, aclcnt, NULL, ',', 0);
+}
+
static mode_t
-permfromstr (char *perm)
+permfromstr (char *perm, bool posix_long)
{
mode_t mode = 0;
+ int idx;
- if (strlen (perm) != 3)
- return 01000;
if (perm[0] == 'r')
mode |= S_IROTH;
else if (perm[0] != '-')
@@ -1529,125 +1728,170 @@ permfromstr (char *perm)
mode |= S_IXOTH;
else if (perm[2] != '-')
return 01000;
- return mode;
+ idx = 3;
+ /* In posix long mode, only tabs up to a hash sign allowed. */
+ if (posix_long)
+ while (perm[idx] == '\t')
+ ++idx;
+ if (perm[idx] == '\0' || (posix_long && perm[idx] == '#'))
+ return mode;
+ return 01000;
}
-extern "C" aclent_t *
-aclfromtext32 (const char *acltextp, int *aclcnt)
+void *
+__aclfromtext (const char *acltextp, int *aclcnt, bool posix)
{
- if (!acltextp || strlen (acltextp) > NT_MAX_PATH)
+ if (!acltextp || strlen (acltextp) >= 2 * NT_MAX_PATH)
{
set_errno (EINVAL);
return NULL;
}
+ cyg_ldap cldap;
tmp_pathbuf tp;
- aclent_t lacl[MAX_ACL_ENTRIES];
- memset (lacl, 0, sizeof lacl);
+ const char *delim;
+ _acl_part *acl_part;
+ char *bufp, *lasts, *qualifier;
int pos = 0;
+ int acl_type;
+
+ aclent_t *lacl = (aclent_t *) tp.c_get ();
+ memset (lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t *));
char *buf = tp.t_get ();
stpcpy (buf, acltextp);
- char *lasts;
- cyg_ldap cldap;
- for (char *c = strtok_r (buf, ",", &lasts);
- c;
- c = strtok_r (NULL, ",", &lasts))
+
+ if (posix)
+ {
+ /* Posix long or short form. Any \n in the string means long form. */
+ if (strchr (buf, '\n'))
+ {
+ delim = "\n";
+ acl_part = acl_part_l;
+ }
+ else
+ {
+ delim = ",";
+ acl_part = acl_part_s;
+ }
+ }
+ else
{
- if (!strncmp (c, "default", 7))
+ /* Solaris aclfromtext format. */
+ delim = ",";
+ acl_part = acl_part_l;
+ }
+
+ for (bufp = strtok_r (buf, delim, &lasts);
+ bufp;
+ bufp = strtok_r (NULL, delim, &lasts))
+ {
+ /* Handle default acl entries only for Solaris ACLs. */
+ if (!posix && _CMP (default_s))
{
lacl[pos].a_type |= ACL_DEFAULT;
- c += 7;
+ bufp += acl_part[default_s].len;
}
- if (!strncmp (c, "user:", 5))
+ lacl[pos].a_id = ACL_UNDEFINED_ID;
+ for (acl_type = user_s; acl_type < none_s; ++acl_type)
+ if (_CMP (acl_type))
+ break;
+ if (acl_type == none_s)
{
- if (c[5] == ':')
- lacl[pos].a_type |= USER_OBJ;
- else
- {
- lacl[pos].a_type |= USER;
- c += 5;
- if (isalpha (*c))
- {
- struct passwd *pw = internal_getpwnam (c, &cldap);
- if (!pw)
- {
- set_errno (EINVAL);
- return NULL;
- }
- lacl[pos].a_id = pw->pw_uid;
- c = strchrnul (c, ':');
- }
- else if (isdigit (*c))
- lacl[pos].a_id = strtol (c, &c, 10);
- if (*c != ':')
- {
- set_errno (EINVAL);
- return NULL;
- }
- }
+ set_errno (EINVAL);
+ return NULL;
}
- else if (!strncmp (c, "group:", 6))
+ bufp += acl_part[acl_type].len;
+ switch (acl_type)
{
- if (c[5] == ':')
- lacl[pos].a_type |= GROUP_OBJ;
- else
+ case user_s:
+ case group_s:
+ qualifier = bufp;
+ bufp = strchrnul (bufp, ':');
+ *bufp++ = '\0';
+ /* No qualifier? USER_OBJ or GROUP_OBJ */
+ if (!*qualifier)
{
- lacl[pos].a_type |= GROUP;
- c += 5;
- if (isalpha (*c))
- {
- struct group *gr = internal_getgrnam (c, &cldap);
- if (!gr)
- {
- set_errno (EINVAL);
- return NULL;
- }
- lacl[pos].a_id = gr->gr_gid;
- c = strchrnul (c, ':');
- }
- else if (isdigit (*c))
- lacl[pos].a_id = strtol (c, &c, 10);
- if (*c != ':')
+ lacl[pos].a_type |= (acl_type == user_s) ? USER_OBJ : GROUP_OBJ;
+ break;
+ }
+ /* Some qualifier, USER or GROUP */
+ lacl[pos].a_type |= (acl_type == user_s) ? USER : GROUP;
+ if (isdigit (*qualifier))
+ {
+ char *ep;
+
+ id_t id = strtol (qualifier, &ep, 10);
+ if (*ep == '\0')
{
- set_errno (EINVAL);
- return NULL;
+ lacl[pos].a_id = id;
+ break;
}
}
- }
- else if (!strncmp (c, "mask:", 5))
- {
- if (c[5] == ':')
- lacl[pos].a_type |= CLASS_OBJ;
+ if (acl_type == user_s)
+ {
+ struct passwd *pw = internal_getpwnam (qualifier, &cldap);
+ if (pw)
+ lacl[pos].a_id = pw->pw_uid;
+ }
else
{
+ struct group *gr = internal_getgrnam (qualifier, &cldap);
+ if (gr)
+ lacl[pos].a_id = gr->gr_gid;
+ }
+ if (lacl[pos].a_id == ACL_UNDEFINED_ID)
+ {
set_errno (EINVAL);
return NULL;
}
- }
- else if (!strncmp (c, "other:", 6))
- {
- if (c[5] == ':')
- lacl[pos].a_type |= OTHER_OBJ;
- else
+ break;
+ case mask_s:
+ case other_s:
+ if (*bufp++ != ':')
{
set_errno (EINVAL);
return NULL;
}
+ lacl[pos].a_type |= (acl_type == mask_s) ? CLASS_OBJ : OTHER_OBJ;
+ break;
}
- if ((lacl[pos].a_perm = permfromstr (c)) == 01000)
+ /* In posix long mode, the next char after the permissions may be a tab
+ followed by effective permissions we can ignore here. */
+ if ((lacl[pos].a_perm = permfromstr (bufp, *delim == '\n')) == 01000)
{
set_errno (EINVAL);
return NULL;
}
++pos;
}
- aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t));
- if (aclp)
+ if (posix)
{
- memcpy (aclp, lacl, pos * sizeof (aclent_t));
- if (aclcnt)
- *aclcnt = pos;
+ acl_t acl = (acl_t) acl_init (pos);
+ if (acl)
+ {
+ memcpy (acl->entry, lacl, pos * sizeof (aclent_t));
+ acl->count = pos;
+ if (aclcnt)
+ *aclcnt = pos;
+ }
+ return (void *) acl;
}
- return aclp;
+ else
+ {
+ aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t));
+ if (aclp)
+ {
+ memcpy (aclp, lacl, pos * sizeof (aclent_t));
+ if (aclcnt)
+ *aclcnt = pos;
+ }
+ return (void *) aclp;
+ }
+}
+
+extern "C" aclent_t *
+aclfromtext32 (char *acltextp, int *aclcnt)
+{
+ return (aclent_t *) __aclfromtext (acltextp, aclcnt, false);
}
#ifdef __x86_64__
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index af3307e..0c37ad2 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -13,7 +13,7 @@ details. */
#include "winsup.h"
#include <stdlib.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include <sys/queue.h>
#include <authz.h>
#include <wchar.h>
diff --git a/winsup/cygwin/sec_posixacl.cc b/winsup/cygwin/sec_posixacl.cc
new file mode 100644
index 0000000..54bac8f
--- /dev/null
+++ b/winsup/cygwin/sec_posixacl.cc
@@ -0,0 +1,1052 @@
+/* sec_posixacl.cc: POSIX ACL functions based on Solaris ACLs.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <unistd.h>
+#include "cygerrno.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "tls_pbuf.h"
+#include "sec_posixacl.h"
+#include <acl/libacl.h>
+
+#define _ENTRY_SIZE(_cnt) ((_cnt) * sizeof (aclent_t))
+#define _ACL_SIZE(_cnt) (sizeof (__acl_ext_t) + _ENTRY_SIZE (_cnt))
+#define ACL_SIZE(_acl) ({ acl_t __acl = _acl; \
+ _ACL_SIZE((__acl)->count - (__acl)->deleted); \
+ })
+#define ACL_PERM_MASK (ACL_READ | ACL_WRITE | ACL_EXECUTE)
+
+extern "C" acl_t
+acl_init (int count)
+{
+ acl_t acl;
+
+ if (count < 0 || count > UINT16_MAX)
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ acl = (acl_t) calloc (1, sizeof (__acl_t));
+ if (!acl)
+ return NULL;
+ acl->entry = (aclent_t *) calloc (count, sizeof (aclent_t));
+ if (!acl->entry)
+ {
+ free (acl);
+ return NULL;
+ }
+ acl->magic = ACL_MAGIC;
+ acl->max_count = count;
+ return acl;
+}
+
+static acl_t
+__acl_dup (acl_t acl, int max)
+{
+ __try
+ {
+ acl_t new_acl = acl_init (max);
+ if (new_acl)
+ {
+ int new_idx = 0;
+
+ for (uint16_t idx = 0; idx < acl->count; ++idx)
+ if (acl->entry[idx].a_type != ACL_DELETED_TAG)
+ new_acl->entry[new_idx++] = acl->entry[idx];
+ new_acl->magic = ACL_MAGIC;
+ new_acl->count = new_idx;
+ new_acl->max_count = max;
+ return new_acl;
+ }
+ }
+ __except (EINVAL) {}
+ __endtry
+ return NULL;
+}
+
+extern "C" acl_t
+acl_dup (acl_t acl)
+{
+ return __acl_dup (acl, acl->max_count);
+}
+
+extern "C" int
+acl_free (void *obj_p)
+{
+ __try
+ {
+ acl_t acl;
+
+ if (obj_p)
+ {
+ if (malloc_usable_size (obj_p) >= sizeof (__acl_t))
+ {
+ acl = (acl_t) obj_p;
+ if (acl->magic == ACL_MAGIC)
+ free (acl->entry);
+ }
+ free (obj_p);
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_valid (acl_t acl)
+{
+ __try
+ {
+ if (!(__aclcheck (acl->entry, acl->count, NULL, true)))
+ return 0;
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_copy_entry (acl_entry_t dest_d, acl_entry_t src_d)
+{
+ __try
+ {
+ uint16_t d_idx, s_idx;
+ acl_t d_acl, s_acl;
+
+ d_acl = __from_entry (dest_d, d_idx);
+ s_acl = __from_entry (src_d, s_idx);
+ if (d_acl && s_acl)
+ {
+ d_acl->entry[d_idx] = s_acl->entry[s_idx];
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_create_entry (acl_t *acl_p, acl_entry_t *entry_p)
+{
+ __try
+ {
+ acl_t acl = *acl_p;
+ uint16_t idx;
+
+ if (acl->deleted > 0)
+ {
+ for (idx = 0; idx < acl->count; ++idx)
+ if (acl->entry[idx].a_type == ACL_DELETED_TAG)
+ {
+ *entry_p = __to_entry (acl, idx);
+ --acl->deleted;
+ goto fill_entry;
+ }
+ }
+ if (acl->count >= acl->max_count)
+ {
+ acl_t new_acl = __acl_dup (acl, acl->count + 1);
+ if (!new_acl)
+ __leave;
+ *acl_p = new_acl;
+ acl_free (acl);
+ acl = *acl_p;
+ }
+ idx = acl->count++;
+ *entry_p = __to_entry (acl, idx);
+ fill_entry:
+ acl->entry[idx].a_type = ACL_UNDEFINED_TAG;
+ acl->entry[idx].a_id = ACL_UNDEFINED_ID;
+ acl->entry[idx].a_perm = 0;
+ return 0;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_delete_entry (acl_t acl, acl_entry_t entry_d)
+{
+ __try
+ {
+ acl_t acl_p;
+ uint16_t idx;
+
+ acl_p = __from_entry (entry_d, idx);
+
+ if (acl_p == acl)
+ {
+ acl_p->entry[idx].a_type = ACL_DELETED_TAG;
+ acl_p->entry[idx].a_id = ACL_UNDEFINED_ID;
+ acl_p->entry[idx].a_perm = 0;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_get_entry (acl_t acl, int entry_id, acl_entry_t *entry_p)
+{
+ __try
+ {
+ uint16_t idx;
+
+ if (entry_id == ACL_FIRST_ENTRY)
+ acl->next = 0;
+ else if (entry_id != ACL_NEXT_ENTRY)
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ do
+ {
+ if (acl->next >= acl->count)
+ return 0;
+ idx = acl->next++;
+ }
+ while (acl->entry[idx].a_type == ACL_DELETED_TAG);
+ *entry_p = __to_entry (acl, idx);
+ return 1;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_calc_mask (acl_t *acl_p)
+{
+ __try
+ {
+ acl_t acl = *acl_p;
+ mode_t mask = 0;
+
+ mask = __aclcalcmask (acl->entry, acl->count);
+ /* If __aclcalcmask returns -1 we're done. Otherwise create a
+ mask entry here. */
+ if (mask != (acl_perm_t) -1)
+ {
+ acl_entry_t entry_d;
+ uint16_t mask_idx;
+
+ if (acl_create_entry (&acl, &entry_d) < 0)
+ __leave;
+ if (!__from_entry (entry_d, mask_idx))
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ acl->entry[mask_idx].a_type = ACL_MASK;
+ acl->entry[mask_idx].a_id = ACL_UNDEFINED_ID;
+ acl->entry[mask_idx].a_perm = mask;
+ *acl_p = acl;
+ }
+ return 0;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_clear_perms (acl_permset_t permset_d)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_permset (permset_d, idx);
+ if (acl)
+ {
+ acl->entry[idx].a_perm = 0;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_add_perm (acl_permset_t permset_d, acl_perm_t perm)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_permset (permset_d, idx);
+ if (acl && !(perm & ~ACL_PERM_MASK))
+ {
+ acl->entry[idx].a_perm |= perm;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_delete_perm (acl_permset_t permset_d, acl_perm_t perm)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_permset (permset_d, idx);
+ if (acl && !(perm & ~ACL_PERM_MASK))
+ {
+ acl->entry[idx].a_perm &= ~perm;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_get_permset (acl_entry_t entry_d, acl_permset_t *permset_p)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_entry (entry_d, idx);
+ if (acl)
+ {
+ *permset_p = (acl_permset_t) entry_d;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_set_permset (acl_entry_t entry_d, acl_permset_t permset_d)
+{
+ __try
+ {
+ acl_t acl_e, acl_p;
+ uint16_t idx_e, idx_p;
+
+ acl_e = __from_entry (entry_d, idx_e);
+ acl_p = __from_permset (permset_d, idx_p);
+ if (acl_e && acl_p && !(acl_p->entry[idx_p].a_perm & ~ACL_PERM_MASK))
+ {
+ acl_e->entry[idx_e].a_perm = acl_p->entry[idx_p].a_perm;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" void *
+acl_get_qualifier (acl_entry_t entry_d)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_entry (entry_d, idx);
+ if (acl && (acl->entry[idx].a_type & (ACL_USER | ACL_GROUP)))
+ {
+ id_t *id = (id_t *) malloc (sizeof (id_t));
+ if (id)
+ {
+ *id = acl->entry[idx].a_id;
+ return (void *) id;
+ }
+ }
+ else
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return NULL;
+}
+
+extern "C" int
+acl_set_qualifier (acl_entry_t entry_d, const void *qualifier_p)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_entry (entry_d, idx);
+ if (acl && (acl->entry[idx].a_type & (ACL_USER | ACL_GROUP)))
+ {
+ acl->entry[idx].a_id = *(id_t *) qualifier_p;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_get_tag_type (acl_entry_t entry_d, acl_tag_t *tag_type_p)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_entry (entry_d, idx);
+ if (acl)
+ {
+ *tag_type_p = acl->entry[idx].a_type;
+ return 0;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_set_tag_type (acl_entry_t entry_d, acl_tag_t tag_type)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_entry (entry_d, idx);
+ if (acl)
+ switch (tag_type)
+ {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ acl->entry[idx].a_id = ACL_UNDEFINED_ID;
+ /*FALLTHRU*/
+ case ACL_USER:
+ case ACL_GROUP:
+ acl->entry[idx].a_type = tag_type;
+ return 0;
+ default:
+ break;
+ }
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" ssize_t
+acl_size (acl_t acl)
+{
+ __try
+ {
+ return (ssize_t) ACL_SIZE (acl);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" ssize_t
+acl_copy_ext (void *buf_p, acl_t acl, ssize_t size)
+{
+ __try
+ {
+ ssize_t ext_size = (ssize_t) ACL_SIZE (acl);
+
+ if (size <= 0)
+ set_errno (EINVAL);
+ else if (ext_size > size)
+ set_errno (ERANGE);
+ else
+ {
+ uint16_t ext_idx = 0;
+ __acl_ext_t *acl_ext = (__acl_ext_t *) buf_p;
+
+ acl_ext->count = acl->count - acl->deleted;
+ for (uint16_t idx = 0; idx < acl->count; ++idx)
+ if (acl->entry[idx].a_type != ACL_DELETED_TAG)
+ acl_ext->entry[ext_idx++] = acl->entry[idx];
+ return ext_size;
+ }
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" acl_t
+acl_copy_int (const void *buf_p)
+{
+ __try
+ {
+ acl_t acl;
+ __acl_ext_t *acl_ext = (__acl_ext_t *) buf_p;
+
+ acl = acl_init (acl_ext->count);
+ if (acl)
+ {
+ memcpy (acl->entry, acl_ext->entry, _ENTRY_SIZE (acl_ext->count));
+ acl->count = acl_ext->count;
+ return acl;
+ }
+ }
+ __except (EINVAL) {}
+ __endtry
+ return NULL;
+}
+
+extern "C" acl_t
+acl_from_text (const char *buf_p)
+{
+ __try
+ {
+ return (acl_t) __aclfromtext (buf_p, NULL, true);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return NULL;
+}
+
+extern "C" char *
+acl_to_text (acl_t acl, ssize_t *len_p)
+{
+ __try
+ {
+ char *ret = __acltotext (acl->entry, acl->count, NULL, '\n',
+ TEXT_IS_POSIX
+ | TEXT_SOME_EFFECTIVE
+ | TEXT_END_SEPARATOR);
+ if (ret && len_p)
+ *len_p = strlen (ret);
+ return ret;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return NULL;
+}
+
+acl_t __reg2
+fhandler_base::acl_get (acl_type_t type)
+{
+ set_errno (ENOTSUP);
+ return NULL;
+}
+
+acl_t __reg2
+fhandler_disk_file::acl_get (acl_type_t type)
+{
+ acl_t acl = NULL;
+ int oret = 0;
+
+ __try
+ {
+ tmp_pathbuf tp;
+ aclent_t *aclbufp;
+ uint16_t cnt, access_cnt;
+
+ if (!pc.has_acls ())
+ {
+ set_errno (ENOTSUP);
+ __leave;
+ }
+ if (type == ACL_TYPE_DEFAULT && !pc.isdir ())
+ {
+ set_errno (ENOTDIR);
+ __leave;
+ }
+ aclbufp = (aclent_t *) tp.c_get ();
+ if (!get_handle ())
+ {
+ query_open (query_read_control);
+ if (!(oret = open (O_BINARY, 0)))
+ __leave;
+ }
+ cnt = facl (GETACL, MAX_ACL_ENTRIES, aclbufp);
+ if (cnt < 0)
+ __leave;
+ /* Set access_cnt to number of non-default entries from file ACL. */
+ if (!pc.isdir ())
+ access_cnt = cnt;
+ else
+ for (access_cnt = 0; access_cnt < cnt; ++access_cnt)
+ if (aclbufp[access_cnt].a_type & ACL_DEFAULT)
+ break;
+ if (type == ACL_TYPE_ACCESS)
+ {
+ acl = acl_init (access_cnt);
+ if (!acl)
+ __leave;
+ memcpy (acl->entry, aclbufp, _ENTRY_SIZE (access_cnt));
+ acl->count = access_cnt;
+ }
+ else
+ {
+ cnt -= access_cnt;
+ acl = acl_init (cnt);
+ if (acl && cnt)
+ {
+ memcpy (acl->entry, aclbufp + access_cnt, _ENTRY_SIZE (cnt));
+ acl->count = cnt;
+ for (cnt = 0; cnt < acl->count; ++cnt)
+ acl->entry[cnt].a_type &= ~ACL_DEFAULT;
+ }
+ }
+ }
+ __except (EINVAL) {}
+ __endtry
+ if (oret)
+ close_fs ();
+ return acl;
+}
+
+extern "C" acl_t
+acl_get_fd (int fd)
+{
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return NULL;
+ return cfd->acl_get (ACL_TYPE_ACCESS);
+}
+
+extern "C" acl_t
+acl_get_file (const char *path_p, acl_type_t type)
+{
+ if (type != ACL_TYPE_ACCESS && type != ACL_TYPE_DEFAULT)
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ fhandler_base *fh;
+ if (!(fh = build_fh_name (path_p, PC_SYM_FOLLOW, stat_suffixes)))
+ return NULL;
+ if (fh->error ())
+ {
+ set_errno (fh->error ());
+ return NULL;
+ }
+ acl_t acl = fh->acl_get (type);
+ delete fh;
+ return acl;
+}
+
+int __reg3
+fhandler_base::acl_set (acl_t acl, acl_type_t type)
+{
+ set_errno (ENOTSUP);
+ return -1;
+}
+
+int __reg3
+fhandler_disk_file::acl_set (acl_t acl, acl_type_t type)
+{
+ int ret = -1;
+ int oret = 0;
+
+ __try
+ {
+ tmp_pathbuf tp;
+ aclent_t *aclbufp, *aclbuf_from_file;
+ uint16_t cnt, cnt_from_file, access_cnt;
+
+ if (!pc.has_acls ())
+ {
+ set_errno (ENOTSUP);
+ __leave;
+ }
+ if (type == ACL_TYPE_DEFAULT && !pc.isdir ())
+ {
+ set_errno (ENOTDIR);
+ __leave;
+ }
+ if (acl->count > MAX_ACL_ENTRIES)
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ aclbuf_from_file = (aclent_t *) tp.c_get ();
+ if (!get_handle ())
+ {
+ query_open (query_write_dac);
+ if (!(oret = open (O_BINARY, 0)))
+ __leave;
+ }
+ cnt_from_file = facl (GETACL, MAX_ACL_ENTRIES, aclbuf_from_file);
+ if (cnt_from_file < 0)
+ __leave;
+ aclbufp = (aclent_t *) tp.c_get ();
+ /* Set access_cnt to number of non-default entries from file ACL. */
+ if (!pc.isdir ())
+ access_cnt = cnt_from_file;
+ else
+ for (access_cnt = 0; access_cnt < cnt_from_file; ++access_cnt)
+ if (aclbuf_from_file[access_cnt].a_type & ACL_DEFAULT)
+ break;
+ if (type == ACL_TYPE_ACCESS)
+ {
+ /* Check if the number of ACEs fits into the buffer. */
+ if (acl->count - acl->deleted + cnt_from_file - access_cnt
+ > MAX_ACL_ENTRIES)
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ /* Copy the new ACL entries. */
+ cnt = 0;
+ for (uint16_t idx = 0; idx < acl->count; ++idx)
+ if (acl->entry[idx].a_type != ACL_DELETED_TAG)
+ aclbufp[cnt++] = acl->entry[idx];
+ /* Append default ACL from file, if any. */
+ if (access_cnt < cnt_from_file)
+ {
+ memcpy (aclbufp + cnt, aclbuf_from_file + access_cnt,
+ _ENTRY_SIZE (cnt_from_file - access_cnt));
+ cnt += cnt_from_file - access_cnt;
+ }
+ }
+ else
+ {
+ /* Check if the number of ACEs fits into the buffer. */
+ if (acl->count - acl->deleted + access_cnt > MAX_ACL_ENTRIES)
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ /* Copy non-default entries from file. */
+ memcpy (aclbufp, aclbuf_from_file, _ENTRY_SIZE (access_cnt));
+ cnt = access_cnt;
+ /* Append new default ACL entries (and add ACL_DEFAULT flag). */
+ for (uint16_t idx = 0; idx < acl->count; ++idx)
+ if (acl->entry[idx].a_type != ACL_DELETED_TAG)
+ {
+ aclbufp[cnt] = acl->entry[idx];
+ aclbufp[cnt++].a_type |= ACL_DEFAULT;
+ }
+ }
+ ret = facl (SETACL, cnt, aclbufp);
+ }
+ __except (EINVAL) {}
+ __endtry
+ if (oret)
+ close_fs ();
+ return ret;
+}
+
+extern "C" int
+acl_set_fd (int fd, acl_t acl)
+{
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return -1;
+ return cfd->acl_set (acl, ACL_TYPE_ACCESS);
+}
+
+extern "C" int
+acl_set_file(const char *path_p, acl_type_t type, acl_t acl)
+{
+ if (type != ACL_TYPE_ACCESS && type != ACL_TYPE_DEFAULT)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ fhandler_base *fh;
+ if (!(fh = build_fh_name (path_p, PC_SYM_FOLLOW, stat_suffixes)))
+ return -1;
+ if (fh->error ())
+ {
+ set_errno (fh->error ());
+ return -1;
+ }
+ int ret = fh->acl_set (acl, type);
+ delete fh;
+ return ret;
+}
+
+extern "C" int
+acl_delete_def_file (const char *path_p)
+{
+ acl_t acl = (acl_t) alloca (sizeof (struct __acl_t));
+ acl->count = acl->max_count = acl->next = 0;
+ if (!acl)
+ return -1;
+ return acl_set_file(path_p, ACL_TYPE_DEFAULT, acl);
+}
+
+/* libacl extensions */
+
+extern "C" int
+acl_check (acl_t acl, int *last)
+{
+
+ __try
+ {
+ int ret = 0;
+
+ if (acl->count != 0)
+ {
+ ret = __aclcheck (acl->entry, acl->count, last, true);
+ switch (ret)
+ {
+ case GRP_ERROR:
+ case USER_ERROR:
+ case CLASS_ERROR:
+ case OTHER_ERROR:
+ ret = ACL_MULTI_ERROR;
+ break;
+ default:
+ break;
+ }
+ }
+ return ret;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_cmp (acl_t acl1, acl_t acl2)
+{
+ int ret = -1;
+
+ __try
+ {
+ tmp_pathbuf tp;
+
+ __acl_ext_t *acl1d = (__acl_ext_t *) tp.c_get ();
+ __acl_ext_t *acl2d = (__acl_ext_t *) tp.c_get ();
+ if (acl_copy_ext (acl1d, acl1, NT_MAX_PATH) < 0)
+ __leave;
+ if (acl_copy_ext (acl2d, acl2, NT_MAX_PATH) < 0)
+ __leave;
+ if (acl1d->count != acl2d->count)
+ return 1;
+ if (__aclsort (acl1d->count, acl1d->entry))
+ __leave;
+ if (__aclsort (acl2d->count, acl2d->entry))
+ __leave;
+ for (int idx = 0; idx < acl1d->count; ++idx)
+ {
+ if (acl1d->entry[idx].a_type != acl2d->entry[idx].a_type)
+ {
+ ret = 1;
+ __leave;
+ }
+ if ((acl1d->entry[idx].a_perm & ACL_PERM_MASK)
+ != (acl2d->entry[idx].a_perm & ACL_PERM_MASK))
+ {
+ ret = 1;
+ __leave;
+ }
+ if ((acl1d->entry[idx].a_type & (ACL_USER | ACL_GROUP))
+ && acl1d->entry[idx].a_id != acl2d->entry[idx].a_id)
+ {
+ ret = 1;
+ __leave;
+ }
+ }
+ ret = 0;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return ret;
+}
+
+extern "C" int
+acl_entries (acl_t acl)
+{
+ __try
+ {
+ return acl->count - acl->deleted;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" int
+acl_equiv_mode (acl_t acl, mode_t *mode_p)
+{
+ __try
+ {
+ if (acl->count != 3)
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ int u_idx = -1, g_idx = -1, o_idx = -1;
+ for (int idx = 0; idx < 3; ++idx)
+ switch (acl->entry[idx].a_type)
+ {
+ case ACL_USER_OBJ:
+ u_idx = idx;
+ break;
+ case ACL_GROUP_OBJ:
+ g_idx = idx;
+ break;
+ case ACL_OTHER:
+ o_idx = idx;
+ break;
+ }
+ if (u_idx == -1 || g_idx == -1 || o_idx == -1)
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
+ if (mode_p)
+ *mode_p = ((acl->entry[u_idx].a_perm & ACL_PERM_MASK) << 6)
+ | ((acl->entry[g_idx].a_perm & ACL_PERM_MASK) << 3)
+ | (acl->entry[o_idx].a_perm & ACL_PERM_MASK);
+ return 0;
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+static const char *acl_err_txt[] =
+{
+ "Multiple entries",
+ "Duplicate entries",
+ "Invalid entry type",
+ "Missing or wrong entry"
+};
+
+extern "C" const char *
+acl_error (int code)
+{
+ if (code < ACL_MULTI_ERROR || code > ACL_MISS_ERROR)
+ return NULL;
+ return acl_err_txt[code - ACL_MULTI_ERROR];
+}
+
+extern "C" int
+acl_extended_fd (int fd)
+{
+ __try
+ {
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ __leave;
+ if (!cfd->pc.has_acls ())
+ {
+ set_errno (ENOTSUP);
+ __leave;
+ }
+ return cfd->facl (GETACLCNT, 0, NULL);
+ }
+ __except (EBADF) {}
+ __endtry
+ return -1;
+}
+
+static int
+__acl_extended_file (const char *path_p, mode_t follow)
+{
+ int fd = open (path_p, O_RDONLY | O_CLOEXEC | follow);
+ if (fd < 0)
+ return -1;
+ int ret = acl_extended_fd (fd);
+ close (fd);
+ return ret;
+}
+
+extern "C" int
+acl_extended_file (const char *path_p)
+{
+ return __acl_extended_file (path_p, 0);
+}
+
+extern "C" int
+acl_extended_file_nofollow (const char *path_p)
+{
+ return __acl_extended_file (path_p, O_NOFOLLOW);
+}
+
+extern "C" acl_t
+acl_from_mode (mode_t mode)
+{
+ acl_t acl = acl_init (MIN_ACL_ENTRIES);
+ if (!acl)
+ return NULL;
+ acl->count = 3;
+ acl->entry[0].a_type = USER_OBJ;
+ acl->entry[0].a_id = ACL_UNDEFINED_ID;
+ acl->entry[0].a_perm = (mode >> 6) & ACL_PERM_MASK;
+ acl->entry[1].a_type = GROUP_OBJ;
+ acl->entry[1].a_id = ACL_UNDEFINED_ID;
+ acl->entry[1].a_perm = (mode >> 3) & ACL_PERM_MASK;
+ acl->entry[2].a_type = OTHER_OBJ;
+ acl->entry[2].a_id = ACL_UNDEFINED_ID;
+ acl->entry[2].a_perm = mode & ACL_PERM_MASK;
+ return acl;
+}
+
+extern "C" int
+acl_get_perm (acl_permset_t permset_d, acl_perm_t perm)
+{
+ __try
+ {
+ acl_t acl;
+ uint16_t idx;
+
+ acl = __from_permset (permset_d, idx);
+ if (acl && !(perm & ~ACL_PERM_MASK))
+ return (~acl->entry[idx].a_perm & perm) ? 0 : 1;
+ set_errno (EINVAL);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return -1;
+}
+
+extern "C" char *
+acl_to_any_text (acl_t acl, const char *prefix, char separator, int options)
+{
+ __try
+ {
+ return __acltotext (acl->entry, acl->count, prefix, separator,
+ TEXT_IS_POSIX | options);
+ }
+ __except (EINVAL) {}
+ __endtry
+ return NULL;
+}
diff --git a/winsup/cygwin/sec_posixacl.h b/winsup/cygwin/sec_posixacl.h
new file mode 100644
index 0000000..a3790a5
--- /dev/null
+++ b/winsup/cygwin/sec_posixacl.h
@@ -0,0 +1,68 @@
+/* sec_posixacl.h: Internal definitions for POSIX ACLs.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <cygwin/acl.h>
+#include <sys/acl.h>
+#include <acl/libacl.h>
+
+/* Magic marker for acl_t. */
+#define ACL_MAGIC (0xacdccdcadcaccacdULL)
+
+/* Only used internally as a_type for deleted entries. */
+#define ACL_DELETED_TAG (0xffff)
+
+/* Only used internally from acl_to_text/acl_to_any_text. */
+#define TEXT_END_SEPARATOR (0x1000)
+#define TEXT_IS_POSIX (0x2000)
+
+/* Internal ACL representation. */
+struct __acl_t
+{
+ uint64_t magic; /* Must be ACL_MAGIC. */
+ uint16_t max_count; /* Max. number of entries. */
+ uint16_t count; /* Number of used entries. */
+ uint16_t deleted; /* Number of used but deleted entries. */
+ uint16_t next; /* Next entry to be returned by acl_get_entry. */
+ aclent_t *entry; /* Pointer to variable array of ACL entries. */
+};
+
+inline acl_entry_t
+__to_entry (acl_t acl, uint16_t idx)
+{
+ return ((uint64_t) idx << 48) | (uint64_t) acl;
+}
+#define __to_permset(a,i) ((acl_permset_t)__to_entry((a),(i)))
+
+inline acl_t
+__from_entry (acl_entry_t entry_d, uint16_t &idx)
+{
+ idx = entry_d >> 48;
+ acl_t acl = (acl_t) (entry_d & ~((uint64_t) 0xffff << 48));
+ if (acl->magic != ACL_MAGIC)
+ return NULL;
+ if (idx >= acl->count)
+ return NULL;
+ if (acl->entry[idx].a_type == ACL_DELETED_TAG)
+ return NULL;
+ return acl;
+}
+#define __from_permset(p,i) __from_entry((acl_permset_t)(p),(i))
+
+/* External (but opaque) ACL representation. */
+struct __acl_ext_t
+{
+ uint16_t count; /* Number of used entries. */
+ aclent_t entry[0]; /* Variable array of ACL entries. */
+};
+
+/* Shared functions defined in sec_acl.cc. */
+mode_t __aclcalcmask (aclent_t *, int);
+int __aclsort (int, aclent_t *);
+int __aclcheck (aclent_t *, int, int *, bool);
+char *__acltotext (aclent_t *, int, const char *, char, int);
+void *__aclfromtext (const char *, int *, bool);
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 4e02bca..b733071 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -15,7 +15,7 @@ details. */
#include "winsup.h"
#include <unistd.h>
#include <stdlib.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include "cygerrno.h"
#include "security.h"
#include "path.h"
diff --git a/winsup/utils/getfacl.c b/winsup/utils/getfacl.c
index 45e5e20..b3a3b9a 100644
--- a/winsup/utils/getfacl.c
+++ b/winsup/utils/getfacl.c
@@ -15,8 +15,7 @@ details. */
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
-#include <sys/types.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include <sys/stat.h>
#include <cygwin/version.h>
#include <string.h>
diff --git a/winsup/utils/setfacl.c b/winsup/utils/setfacl.c
index cd0edc5..ea9447c 100644
--- a/winsup/utils/setfacl.c
+++ b/winsup/utils/setfacl.c
@@ -20,8 +20,7 @@ details. */
#include <getopt.h>
#include <pwd.h>
#include <grp.h>
-#include <sys/types.h>
-#include <sys/acl.h>
+#include <cygwin/acl.h>
#include <cygwin/version.h>
#ifndef BOOL