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>
This commit is contained in:
Corinna Vinschen 2016-01-06 18:41:36 +01:00
parent edd7d93484
commit 9ddf063921
18 changed files with 1849 additions and 300 deletions

View 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 $@ $?

View 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

View 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"

View 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);

View 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"

View 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"

View 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"

View 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"

View File

@ -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 */

View 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

View 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 */

View 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,23 +1176,35 @@ 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)
{
/* 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:
@ -1289,16 +1302,25 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
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)
switch (aclbufp[idx].a_type)
{
if (aclbufp[idx].a_type == CLASS_OBJ)
mask_idx = idx;
else if (aclbufp[idx].a_type
& (USER | GROUP_OBJ | GROUP))
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];
*bufp++ = (perm & S_IROTH) ? 'r' : '-';
*bufp++ = (perm & S_IWOTH) ? 'w' : '-';
*bufp++ = (perm & S_IXOTH) ? 'x' : '-';
return bufp;
}
pbuf[0] = (perm & S_IROTH) ? 'r' : '-';
pbuf[1] = (perm & S_IWOTH) ? 'w' : '-';
pbuf[2] = (perm & S_IXOTH) ? 'x' : '-';
pbuf[3] = '\0';
return pbuf;
#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
|| aclsort32 (aclcnt, 0, aclbufp))
{
set_errno (EINVAL);
return NULL;
}
cyg_ldap cldap;
tmp_pathbuf tp;
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;
*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)
{
_CHK (1);
*bufp++ = separator;
}
first = false;
/* 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:
case USER:
_CPY (acl_part[user_s].str);
break;
case GROUP_OBJ:
case GROUP:
_CPY (acl_part[group_s].str);
break;
case CLASS_OBJ:
_CPY (acl_part[mask_s].str);
break;
case OTHER_OBJ:
_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:
_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)
{
if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES
|| aclcheck32 (aclbufp, aclcnt, NULL))
{
set_errno (EINVAL);
return NULL;
}
tmp_pathbuf tp;
char *buf = tp.c_get ();
buf[0] = '\0';
bool first = true;
for (int pos = 0; pos < aclcnt; ++pos)
{
if (!first)
strcat (buf, ",");
first = false;
if (aclbufp[pos].a_type & ACL_DEFAULT)
strcat (buf, "default");
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));
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));
break;
case CLASS_OBJ:
__small_sprintf (buf + strlen (buf), "mask::%s",
permtostr (aclbufp[pos].a_perm));
break;
case OTHER_OBJ:
__small_sprintf (buf + strlen (buf), "other::%s",
permtostr (aclbufp[pos].a_perm));
break;
default:
set_errno (EINVAL);
return NULL;
}
}
return strdup (buf);
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,117 +1728,155 @@ permfromstr (char *perm)
mode |= S_IXOTH;
else if (perm[2] != '-')
return 01000;
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)
{
if (!strncmp (c, "default", 7))
/* 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
{
/* 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))
{
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)
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)
{
set_errno (EINVAL);
return NULL;
}
bufp += acl_part[acl_type].len;
switch (acl_type)
{
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 |= (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')
{
lacl[pos].a_id = id;
break;
}
}
if (acl_type == user_s)
{
struct passwd *pw = internal_getpwnam (qualifier, &cldap);
if (pw)
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;
}
}
}
else if (!strncmp (c, "group:", 6))
{
if (c[5] == ':')
lacl[pos].a_type |= GROUP_OBJ;
else
{
lacl[pos].a_type |= GROUP;
c += 5;
if (isalpha (*c))
{
struct group *gr = internal_getgrnam (c, &cldap);
if (!gr)
{
set_errno (EINVAL);
return NULL;
}
struct group *gr = internal_getgrnam (qualifier, &cldap);
if (gr)
lacl[pos].a_id = gr->gr_gid;
c = strchrnul (c, ':');
}
else if (isdigit (*c))
lacl[pos].a_id = strtol (c, &c, 10);
if (*c != ':')
if (lacl[pos].a_id == ACL_UNDEFINED_ID)
{
set_errno (EINVAL);
return NULL;
}
}
}
else if (!strncmp (c, "mask:", 5))
{
if (c[5] == ':')
lacl[pos].a_type |= CLASS_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;
}
else if (!strncmp (c, "other:", 6))
{
if (c[5] == ':')
lacl[pos].a_type |= OTHER_OBJ;
else
{
set_errno (EINVAL);
return NULL;
}
}
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;
}
if (posix)
{
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;
}
else
{
aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t));
if (aclp)
{
@ -1647,7 +1884,14 @@ aclfromtext32 (const char *acltextp, int *aclcnt)
if (aclcnt)
*aclcnt = pos;
}
return aclp;
return (void *) aclp;
}
}
extern "C" aclent_t *
aclfromtext32 (char *acltextp, int *aclcnt)
{
return (aclent_t *) __aclfromtext (acltextp, aclcnt, false);
}
#ifdef __x86_64__

View 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>

File diff suppressed because it is too large Load Diff

View File

@ -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);

View 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"

View 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>

View 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