]> sourceware.org Git - newlib-cygwin.git/commitdiff
Implement POSIX.1e ACL functions
authorCorinna Vinschen <corinna@vinschen.de>
Wed, 6 Jan 2016 17:41:36 +0000 (18:41 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Tue, 8 Mar 2016 12:56:40 +0000 (13:56 +0100)
* 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>
18 files changed:
winsup/cygwin/Makefile.in
winsup/cygwin/common.din
winsup/cygwin/fhandler.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/fhandler_socket.cc
winsup/cygwin/fhandler_tty.cc
winsup/cygwin/fhandler_virtual.cc
winsup/cygwin/include/acl/libacl.h [new file with mode: 0644]
winsup/cygwin/include/cygwin/version.h
winsup/cygwin/include/sys/acl.h
winsup/cygwin/sec_acl.cc
winsup/cygwin/sec_helper.cc
winsup/cygwin/sec_posixacl.cc [new file with mode: 0644]
winsup/cygwin/sec_posixacl.h [new file with mode: 0644]
winsup/cygwin/security.cc
winsup/utils/getfacl.c
winsup/utils/setfacl.c

index 271a5be1b56d1c0be9f115907a9677a8928cfa70..fac9b3e0d5a446ee1850fa94893cd619c80cd448 100644 (file)
@@ -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 $@ $?
 
index c39d2650525bb77f788351d2b9bb973f61e7a799..fe714d874e9cd03ba42b0a60d95921ded7514419 100644 (file)
@@ -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
index 7e4d996ce0ea3546b9dba4316ea460f1c23a0521..33743d44d866784c03b28b73488993e35d40b166 100644 (file)
@@ -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"
index d94f38d986dce23d60fd82797fd230a3a7828c88..134fd716bbfcbb70130240cacfbdd9a43f0a99ba 100644 (file)
@@ -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);
index 7d729e3ad8f881bd9a8b7b303883fbf7555d0858..470dae872b6cdd619e67771c4ff7d08336746373 100644 (file)
@@ -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"
index 7d3efad9bef706163404035abba2986b3494b187..990cdc71385833747618886a978f7bc85462fc9e 100644 (file)
@@ -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"
index ee37ed48c7462252f70bf2c318602edf1b4134af..a39a5667496a90ee6c36e116d37ab1af56611626 100644 (file)
@@ -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"
index 2d56d7413d64f1e501b1ce0917df6e8479014944..8f302a75896d6bba1c7b4b5750b3daa3983c7e49 100644 (file)
@@ -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 (file)
index 0000000..b93d686
--- /dev/null
@@ -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 */
index be85ce14ff12150eb295183071cba9a9521a3da8..4edb8dbc885576022baf737ea47dff3c7cd2f1ae 100644 (file)
@@ -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
index 89c38bc0fdf6ca7633b379eda638ea25b4cba611..c3a9fc1afe30870b22e525d2237509b56d72967f 100644 (file)
@@ -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 */
index de40717dc81129ef4e2e46ebcce387773227b015..052856ffd70f56151374845fca8d450c405d93bc 100644 (file)
@@ -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__
index af3307eb44b9c6b7d51970944c0f6f72a63d061a..0c37ad2b7b7b8f6b732e09a4e68941f2ed26cbbd 100644 (file)
@@ -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 (file)
index 0000000..54bac8f
--- /dev/null
@@ -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 (file)
index 0000000..a3790a5
--- /dev/null
@@ -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);
index 4e02bca2e93448669fb4145941dc74eded58b0da..b7330717a0570ddc2c24955218c3070e68d22aa4 100644 (file)
@@ -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"
index 45e5e2090e3764cdc91004bd08b3cd3fb18c2a5f..b3a3b9ac7fb32aebb1f27d6bf1040aae489d79ca 100644 (file)
@@ -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>
index cd0edc5e3dc4eb0a88b504f92cabc4736a7057b5..ea9447ca6a870a27d41ac5354ebfd4d3b0091d09 100644 (file)
@@ -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
This page took 0.088866 seconds and 5 git commands to generate.