AC_CHECK_HEADERS(errno.h fcntl.h limits.h unistd.h sys/time.h utmp.h \
utmpx.h termios.h termio.h sgtty.h sys/ioctl.h syslog.h paths.h \
utime.h ulimit.h sys/resource.h gshadow.h lastlog.h \
- locale.h rpc/key_prot.h netdb.h)
+ locale.h rpc/key_prot.h netdb.h acl/libacl.h attr/libattr.h
+ attr/error_context.h)
dnl shadow now uses the libc's shadow implementation
AC_CHECK_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
AC_ARG_WITH(selinux,
[AC_HELP_STRING([--with-selinux], [use SELinux support @<:@default=yes if found@:>@])],
[with_selinux=$withval], [with_selinux=maybe])
+AC_ARG_WITH(acl,
+ [AC_HELP_STRING([--with-acl], [use ACL support @<:@default=yes if found@:>@])],
+ [AC_HELP_STRING([--with-attr], [use Extended Attribute support @<:@default=yes if found@:>@])],
+ [with_attr=$withval], [with_attr=maybe])
AC_ARG_WITH(skey,
[AC_HELP_STRING([--with-skey], [use S/Key support @<:@default=no@:>@])],
[with_skey=$withval], [with_skey=no])
AC_CHECK_LIB(crypt, crypt, [LIBCRYPT=-lcrypt],
[AC_MSG_ERROR([crypt() not found])])
+AC_SUBST(LIBACL)
+if test "$with_acl" != "no"; then
+ AC_CHECK_HEADERS(acl/libacl.h attr/error_context.h, [acl_header="yes"], [acl_header="no"])
+ if test "$acl_header$with_acl" = "noyes" ; then
+ AC_MSG_ERROR([acl/libacl.h or attr/error_context.h is missing])
+ elif test "$acl_header" = "yes" ; then
+ AC_CHECK_LIB(acl, perm_copy_file,
+ [AC_CHECK_LIB(acl, perm_copy_fd,
+ [acl_lib="yes"],
+ [acl_lib="no"])],
+ [acl_lib="no"])
+ if test "$acl_lib$with_acl" = "noyes" ; then
+ AC_MSG_ERROR([libacl not found])
+ elif test "$acl_lib" = "no" ; then
+ with_acl="no"
+ else
+ AC_DEFINE(WITH_ACL, 1,
+ [Build shadow with ACL support])
+ LIBACL="-lacl"
+ with_acl="yes"
+ fi
+ else
+ with_acl="no"
+ fi
+fi
+
+AC_SUBST(LIBATTR)
+if test "$with_attr" != "no"; then
+ AC_CHECK_HEADERS(attr/libattr.h attr/error_context.h, [attr_header="yes"], [attr_header="no"])
+ if test "$attr_header$with_attr" = "noyes" ; then
+ AC_MSG_ERROR([attr/libattr.h or attr/error_context.h is missing])
+ elif test "$attr_header" = "yes" ; then
+ AC_CHECK_LIB(attr, attr_copy_file,
+ [AC_CHECK_LIB(attr, attr_copy_fd,
+ [attr_lib="yes"],
+ [attr_lib="no"])],
+ [attr_lib="no"])
+ if test "$attr_lib$with_attr" = "noyes" ; then
+ AC_MSG_ERROR([libattr not found])
+ elif test "$attr_lib" = "no" ; then
+ with_attr="no"
+ else
+ AC_DEFINE(WITH_ATTR, 1,
+ [Build shadow with Extended Attributes support])
+ LIBACL="-lattr"
+ with_attr="yes"
+ fi
+ else
+ with_attr="no"
+ fi
+fi
+
AC_SUBST(LIBAUDIT)
if test "$with_audit" != "no"; then
AC_CHECK_HEADER(libaudit.h, [audit_header="yes"], [audit_header="no"])
echo " suid account management tools: $enable_acct_tools_setuid"
fi
echo " SELinux support: $with_selinux"
+echo " ACL support: $with_acl"
+echo " Extended Attributes support: $with_attr"
echo " tcb support (incomplete): $with_tcb"
echo " shadow group support: $enable_shadowgrp"
echo " S/Key support: $with_skey"
#ifdef WITH_SELINUX
#include <selinux/selinux.h>
#endif /* WITH_SELINUX */
+#if defined(WITH_ACL) || defined(WITH_ATTR)
+#include <attr/error_context.h>
+#endif /* WITH_ACL || WITH_ATTR */
+#ifdef WITH_ACL
+#include <acl/libacl.h>
+#endif /* WITH_ACL */
+#ifdef WITH_ATTR
+#include <attr/libattr.h>
+#endif /* WITH_ATTR */
+
static /*@null@*/const char *src_orig;
static /*@null@*/const char *dst_orig;
#endif /* S_IFLNK */
static int copy_hardlink (const char *src, const char *dst,
struct link_name *lp);
-static int copy_special (const char *dst,
+static int copy_special (const char *src, const char *dst,
const struct stat *statp, const struct timeval mt[],
long int uid, long int gid);
static int copy_file (const char *src, const char *dst,
}
#endif /* WITH_SELINUX */
+#if defined(WITH_ACL) || defined(WITH_ATTR)
+void error (struct error_context *ctx, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ (void) fprintf (stderr, _("%s: "), Prog);
+ if (vfprintf (stderr, fmt, ap) != 0) {
+ (void) fputs (_(": "), stderr);
+ }
+ (void) fprintf (stderr, "%s\n", strerror (errno));
+ va_end (ap);
+}
+
+struct error_context ctx = {
+ error
+};
+#endif /* WITH_ACL || WITH_ATTR */
+
/*
* remove_link - delete a link from the linked list
*/
*/
else if (!S_ISREG (sb.st_mode)) {
- err = copy_special (dst, &sb, mt, uid, gid);
+ err = copy_special (src, dst, &sb, mt, uid, gid);
}
/*
|| (chown (dst,
(uid == - 1) ? statp->st_uid : (uid_t) uid,
(gid == - 1) ? statp->st_gid : (gid_t) gid) != 0)
+#ifdef WITH_ACL
+ || (perm_copy_file (src, dst, &ctx) != 0)
+#else /* !WITH_ACL */
|| (chmod (dst, statp->st_mode) != 0)
+#endif /* !WITH_ACL */
+#ifdef WITH_ATTR
+ /*
+ * If the third parameter is NULL, all extended attributes
+ * except those that define Access Control Lists are copied.
+ * ACLs are excluded by default because copying them between
+ * file systems with and without ACL support needs some
+ * additional logic so that no unexpected permissions result.
+ */
+ || (attr_copy_file (src, dst, NULL, &ctx) != 0)
+#endif /* WITH_ATTR */
|| (copy_tree (src, dst, uid, gid) != 0)
|| (utimes (dst, mt) != 0)) {
err = -1;
|| (lchown (dst,
(uid == -1) ? statp->st_uid : (uid_t) uid,
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
+ /* FIXME: there are no modes on symlinks, right?
+ * ACL could be copied, but this would be much more
+ * complex than calling perm_copy_file.
+ * Ditto for Extended Attributes.
+ * We currently only document that ACL and Extended
+ * Attributes are not copied.
+ */
free (oldlink);
return -1;
}
static int copy_hardlink (const char *src, const char *dst,
struct link_name *lp)
{
- /* TODO: selinux needed? */
+ /* TODO: selinux, ACL, Extended Attributes needed? */
if (link (lp->ln_name, dst) != 0) {
return -1;
*
* Return 0 on success, -1 on error.
*/
-static int copy_special (const char *dst,
+static int copy_special (const char *src, const char *dst,
const struct stat *statp, const struct timeval mt[],
long int uid, long int gid)
{
|| (chown (dst,
(uid == -1) ? statp->st_uid : (uid_t) uid,
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
+#ifdef WITH_ACL
+ || (perm_copy_file (src, dst, &ctx) != 0)
+#else /* !WITH_ACL */
|| (chmod (dst, statp->st_mode & 07777) != 0)
+#endif /* !WITH_ACL */
+#ifdef WITH_ATTR
+ /*
+ * If the third parameter is NULL, all extended attributes
+ * except those that define Access Control Lists are copied.
+ * ACLs are excluded by default because copying them between
+ * file systems with and without ACL support needs some
+ * additional logic so that no unexpected permissions result.
+ */
+ || (attr_copy_file (src, dst, NULL, &ctx) != 0)
+#endif /* WITH_ATTR */
|| (utimes (dst, mt) != 0)) {
err = -1;
}
|| (fchown (ofd,
(uid == -1) ? statp->st_uid : (uid_t) uid,
(gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
- || (fchmod (ofd, statp->st_mode & 07777) != 0)) {
+#ifdef WITH_ACL
+ || (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
+#else /* !WITH_ACL */
+ || (fchmod (ofd, statp->st_mode & 07777) != 0)
+#endif /* !WITH_ACL */
+#ifdef WITH_ATTR
+ /*
+ * If the third parameter is NULL, all extended attributes
+ * except those that define Access Control Lists are copied.
+ * ACLs are excluded by default because copying them between
+ * file systems with and without ACL support needs some
+ * additional logic so that no unexpected permissions result.
+ */
+ || (attr_copy_fd (src, ifd, dst, ofd, NULL, &ctx) != 0)
+#endif /* WITH_ATTR */
+ ) {
(void) close (ifd);
return -1;
}