diff --git a/ChangeLog b/ChangeLog index bd1a8675..fbb37653 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2010-03-30 Nicolas François + + * NEWS, configure.in, libmisc/copydir.c, man/useradd.8.xml, + man/usermod.8.xml, src/Makefile.am: Added support for ACLs and + Extended Attributes. + 2010-03-30 Nicolas François * libmisc/copydir.c: Document the sections closed by #endif diff --git a/NEWS b/NEWS index a4a0b293..d90d7991 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,9 @@ shadow-4.1.4.2 -> shadow-4.1.5 UNRELEASED zero) when explicitly requested (e.g. with --help). * initial support for tcb (http://openwall.com/tcb/) for useradd, userdel, usermod, chage, pwck, vipw. + * Added support for ACLs and Extended Attributes in useradd and usermod. + Support shall be enabled with the new --with-acl or --with-attr + configure options. -chpasswd * PAM enabled versions: restore the -e option to allow restoring diff --git a/TODO b/TODO index 1e68387d..24917a10 100644 --- a/TODO +++ b/TODO @@ -120,4 +120,7 @@ ALL: - su - add a login.defs configuration parameter to add variables to keep in - the environment with "su -l" (TERM/TERMCOLOR/... + the environment with "su -l" (TERM/TERMCOLOR/...) + +- vipw + - set ACT and XATTR on the temporary file (and backups?) diff --git a/configure.in b/configure.in index 584ce7b5..3aa84d5d 100644 --- a/configure.in +++ b/configure.in @@ -33,7 +33,8 @@ AC_HEADER_STDBOOL 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])]) @@ -246,6 +247,10 @@ AC_ARG_WITH(libpam, 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]) @@ -319,6 +324,58 @@ AC_SUBST(LIBCRYPT) 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"]) @@ -565,6 +622,8 @@ if test "$with_libpam" = "yes"; then 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" diff --git a/libmisc/copydir.c b/libmisc/copydir.c index 51578a5b..c48e7c5d 100644 --- a/libmisc/copydir.c +++ b/libmisc/copydir.c @@ -45,6 +45,16 @@ #ifdef WITH_SELINUX #include #endif /* WITH_SELINUX */ +#if defined(WITH_ACL) || defined(WITH_ATTR) +#include +#endif /* WITH_ACL || WITH_ATTR */ +#ifdef WITH_ACL +#include +#endif /* WITH_ACL */ +#ifdef WITH_ATTR +#include +#endif /* WITH_ATTR */ + static /*@null@*/const char *src_orig; static /*@null@*/const char *dst_orig; @@ -70,7 +80,7 @@ static int copy_symlink (const char *src, const char *dst, #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, @@ -119,6 +129,25 @@ int selinux_file_context (const char *dst_name) } #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 */ @@ -369,7 +398,7 @@ static int copy_entry (const char *src, const char *dst, */ else if (!S_ISREG (sb.st_mode)) { - err = copy_special (dst, &sb, mt, uid, gid); + err = copy_special (src, dst, &sb, mt, uid, gid); } /* @@ -413,7 +442,21 @@ static int copy_dir (const char *src, const char *dst, || (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; @@ -514,6 +557,13 @@ static int copy_symlink (const char *src, const char *dst, || (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; } @@ -542,7 +592,7 @@ static int copy_symlink (const char *src, const char *dst, 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; @@ -574,7 +624,7 @@ static int copy_hardlink (const char *src, const char *dst, * * 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) { @@ -588,7 +638,21 @@ static int copy_special (const char *dst, || (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; } @@ -628,7 +692,22 @@ static int copy_file (const char *src, const char *dst, || (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; } diff --git a/man/useradd.8.xml b/man/useradd.8.xml index b2c4ea36..eb3adeb7 100644 --- a/man/useradd.8.xml +++ b/man/useradd.8.xml @@ -273,6 +273,9 @@ /etc/default/useradd or, by default, /etc/skel. + + If possible, the ACLs and extended attributes are copied. + diff --git a/man/usermod.8.xml b/man/usermod.8.xml index f2499574..0a948630 100644 --- a/man/usermod.8.xml +++ b/man/usermod.8.xml @@ -223,6 +223,11 @@ This option is only valid in combination with the (or ) option. + + usermod will try to adapt the ownership of the + files and to copy the modes, ACL and extended attributes, but + manual changes might be needed afterwards. + diff --git a/src/Makefile.am b/src/Makefile.am index 9bfd6ec0..8ca53cb4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -106,9 +106,9 @@ su_SOURCES = \ suauth.c su_LDADD = $(LDADD) $(LIBPAM) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) sulogin_LDADD = $(LDADD) $(LIBCRYPT) -useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) +useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBACL) userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) +usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBACL) vipw_LDADD = $(LDADD) $(LIBSELINUX) install-am: all-am