diff options
143 files changed, 12399 insertions, 0 deletions
@@ -0,0 +1,79 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = . +HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(TOPDIR)/include/builddefs +endif + +CONFIGURE = configure include/builddefs +LSRCFILES = configure configure.in Makepkgs install-sh README VERSION + +LDIRT = config.log .dep config.status config.cache confdefs.h conftest* \ + Logs/* built .census install.* install-dev.* install-lib.* *.gz + +SUBDIRS = include man build libacl getfacl setfacl + +default: $(CONFIGURE) +ifeq ($(HAVE_BUILDDEFS), no) + $(MAKE) -C . $@ +else + $(SUBDIRS_MAKERULE) +endif + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(BUILDRULES) +else +clean: # if configure hasn't run, nothing to clean +endif + +$(CONFIGURE): + autoconf + ./configure + touch .census + +install: default + $(SUBDIRS_MAKERULE) + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) + $(INSTALL) -m 644 README $(PKG_DOC_DIR) + +install-dev: default + $(SUBDIRS_MAKERULE) + +install-lib: default + $(SUBDIRS_MAKERULE) + +realclean distclean: clean + rm -f $(LDIRT) $(CONFIGURE) + [ ! -d Logs ] || rmdir Logs @@ -0,0 +1,111 @@ +#! /bin/sh +# +# Make whichever packages have been requested. +# Defaults to RPMs. +# +LOGDIR=Logs + +type=rpm +verbose=false + +MAKE=${MAKE:-make} +test ! -z "$MAKE" && make=$MAKE + +for opt in $* +do + case "$opt" in + clean) + ;; # ignored, kept for backward compatibility + rpm) + type=rpm ;; + debian) + type=debian ;; + verbose) + verbose=true ;; + *) + echo "Usage: Makepkgs [verbose] [debian|rpm]"; exit 1 ;; + esac +done + +# start with a clean manifest +test -f files.rpm && rm -f files.rpm +test -f filesdevel.rpm && rm -f filesdevel.rpm +test -f fileslib.rpm && rm -f fileslib.rpm + +test ! -d $LOGDIR && mkdir $LOGDIR +rm -rf $LOGDIR/* > /dev/null 2>&1 + +# build Debian packages, cleans itself before starting +SUDO=${SUDO:-sudo} +test ! -z "$SUDO" && sudo=$SUDO +if [ $type = debian ] ; then + LOGDEB=`pwd` + LOGDEB=../`basename $LOGDEB`.log + echo "== Debian build, log is $LOGDEB"; echo + if $verbose ; then + dpkg-buildpackage -r$SUDO | tee $LOGDEB + else + dpkg-buildpackage -r$SUDO > $LOGDEB + fi + exit 0 +fi + +# build RPM packages - manual clean before starting +echo "== clean, log is $LOGDIR/clean" +if $verbose ; then + $MAKE clean 2>&1 | tee $LOGDIR/clean +else + $MAKE clean > $LOGDIR/clean 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE clean\" failed, see log in $LOGDIR/clean + tail $LOGDIR/clean + exit 1 +fi + +echo +echo "== configure, log is $LOGDIR/configure" +rm -f .census # force configure to run here +if $verbose ; then + autoconf 2>&1 | tee $LOGDIR/configure + ./configure 2>&1 | tee -a $LOGDIR/configure +else + autoconf > $LOGDIR/configure 2>&1 + ./configure >> $LOGDIR/configure 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"configure\" failed, see log in $LOGDIR/configure + tail $LOGDIR/configure + exit 1 +fi + +echo +echo "== default, log is $LOGDIR/default" +if $verbose ; then + $MAKE default 2>&1 | tee $LOGDIR/default +else + $MAKE default > $LOGDIR/default 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE default\" failed, see log in $LOGDIR/default + tail $LOGDIR/default + exit 1 +fi + +echo +echo "== dist, log is $LOGDIR/dist" +[ ! -f .census ] && touch .census +if $verbose ; then + $MAKE -C build dist 2>&1 | tee $LOGDIR/dist +else + $MAKE -C build dist > $LOGDIR/dist 2>&1 +fi +if [ $? -ne 0 ] ; then + echo $MAKE dist failed, see log in $LOGDIR/dist + tail $LOGDIR/dist + exit 1 +else + grep '^Wrote:' $LOGDIR/dist | sed -e 's/\.\.\/\.\.\///' +fi + +exit 0 @@ -0,0 +1,19 @@ +Access control list package README +__________________________________ + +See the file doc/INSTALL for build, installation and post- +install configuration steps. + +Refer to the acl(5) manual page for general access control list +information and references to other related manual pages. + +The extended attributes and access control list project for the +ext2 and ext3 filesystems is located at: + http://acl.bestbits.at/ + +For more information and details on how to contribute to the +XFS project see the web pages at: + http://oss.sgi.com/projects/xfs/ + +For more information on the build process, please refer to +the doc/PORTING document. @@ -0,0 +1,7 @@ +# +# This file is used by configure to get version information +# +PKG_MAJOR=0 +PKG_MINOR=8 +PKG_REVISION=7 +PKG_BUILD=0 diff --git a/build/Makefile b/build/Makefile index e69de29..fe11617 100644 --- a/build/Makefile +++ b/build/Makefile @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +MANIFEST=src-manifest +SRCTAR=$(PKG_NAME)-$(PKG_VERSION).src.tar.gz + +LDIRT = *-manifest *.gz $(TOPDIR)/$(PKG_NAME)-* + +# for clean and clobber +SUBDIRS = tar rpm + +# nothing to build here (it's all packaging) +default install install-dev install-lib: + +include $(BUILDRULES) + +# Symlink in the TOPDIR is used to pack files relative to +# product-version directory. +$(MANIFEST) : $(_FORCE) + @if [ ! -L $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ] ; then \ + $(LN_S) . $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ; \ + fi + @CDIR=`pwd`; cd $(TOPDIR); \ + $(MAKE) --no-print-directory source | \ + sed -e 's/^\./$(PKG_NAME)-$(PKG_VERSION)/' > $$CDIR/$@ ;\ + if [ $$? -ne 0 ] ; then \ + exit 1; \ + else \ + unset TAPE; \ + $(TAR) -T $$CDIR/$@ -cf - | $(ZIP) --best > $$CDIR/$(SRCTAR); \ + fi + +dist : default $(MANIFEST) + @DIST_MANIFEST=`pwd`/bin-manifest; DIST_ROOT=/tmp/$$$$; \ + export DIST_MANIFEST DIST_ROOT; \ + rm -f $$DIST_MANIFEST; \ + echo === install === && $(MAKE) -C $(TOPDIR) install || exit $$?; \ + if [ -x $(TAR) ]; then \ + ( echo "=== tar ===" && $(MAKEF) -C tar $@ || exit $$? ); \ + fi; \ + if [ -x $(RPM) ]; then \ + ( echo "=== rpm ===" && $(MAKEF) -C rpm $@ || exit $$? ); \ + fi; \ + test -z "$$KEEP_DIST_ROOT" || rm -rf $$DIST_ROOT; echo Done diff --git a/build/rpm/Makefile b/build/rpm/Makefile index e69de29..1b994c9 100644 --- a/build/rpm/Makefile +++ b/build/rpm/Makefile @@ -0,0 +1,78 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +TREEROOT = $(shell cd ${TOPDIR}; pwd) +include $(TOPDIR)/include/builddefs + +SPECF = $(PKG_NAME).spec +LDIRT = $(PKG_NAME)*.rpm $(SPECF) rpmmacros rpm-*.rc $(TOPDIR)/files*.rpm + +LSRCFILES = macros.template $(SPECF).in rpm-2.rc.template + +default install install-dev install-lib: + +include $(BUILDRULES) + +# generate a binary rpm file +dist : default $(SPECF) rpm-$(RPM_VERSION).rc + $(RPM) -ba --rcfile ./rpm-$(RPM_VERSION).rc $(SPECF) + +# Because rpm prior to v.2.90 does not support macros and old style config +# is not supported by rpm v.3, we have to resort to such ugly hacks +ifneq ($(RPM_VERSION),2) +rpm-$(RPM_VERSION).rc : rpmmacros + sed -e '/^macrofiles:/s|~/.rpmmacros|rpmmacros|' </usr/lib/rpm/rpmrc >$@ + +rpmmacros : macros.template + @sed -e 's|%topdir%|$(TREEROOT)|g' < $< > $@ +else +rpm-2.rc: rpm-2.rc.template + @sed -e 's|%topdir%|$(TOPDIR)|g' < $< > $@ +endif + +.PHONY: $(SPECF) +${SPECF} : ${SPECF}.in + sed -e's|@pkg_name@|$(PKG_NAME)|g' \ + -e's|@pkg_version@|$(PKG_VERSION)|g' \ + -e's|@pkg_release@|$(PKG_RELEASE)|g' \ + -e's|@pkg_distribution@|$(PKG_DISTRIBUTION)|g' \ + -e's|@pkg_builder@|$(PKG_BUILDER)|g' \ + -e's|@build_root@|$(DIST_ROOT)|g' \ + -e'/^BuildRoot: *$$/d' \ + -e's|@pkg_var_dir@|$(PKG_VAR_DIR)|g' \ + -e's|@pkg_share_dir@|$(PKG_SHARE_DIR)|g' \ + -e's|@pkg_log_dir@|$(PKG_LOG_DIR)|g' \ + -e's|@pkg_doc_dir@|$(PKG_DOC_DIR)|g' \ + -e's|@pkg_man_dir@|$(PKG_MAN_DIR)|g' \ + -e's|@pkg_tmp_dir@|$(PKG_TMP_DIR)|g' \ + -e's|@make@|$(MAKE)|g' < $< > $@ diff --git a/build/rpm/acl.spec.in b/build/rpm/acl.spec.in index e69de29..b888a80 100644 --- a/build/rpm/acl.spec.in +++ b/build/rpm/acl.spec.in @@ -0,0 +1,99 @@ +Summary: Access control list utilities. +Name: @pkg_name@-util +Version: @pkg_version@ +Release: @pkg_release@ +Packager: @pkg_builder@ +BuildRoot: @build_root@ +Source: @pkg_name@-@pkg_version@.src.tar.gz +Copyright: GPL +Vendor: Andreas Gruenbacher <a.gruenbacher@computer.org> +Group: System Environment/Base +URL: http://acl.bestbits.at/ + +# This really should be defined as the empty string, but RPM doesn't +# seem to support this. (No more luck with %undefine, either.) +# We end up with definitions like _libdir = "//lib". +%define _exec_prefix / + +%description +This package contains the getfacl and setfacl utilities needed for +manipulating access control lists. + +%package -n libacl +Summary: Dynamic library for access control list support. +Group: Development/Libraries +Prereq: /sbin/ldconfig + +%description -n libacl +This package contains the libacl.so dynamic library which contains +the POSIX 1003.1e draft standard 17 functions for manipulating access +control lists. + +%package -n acl-devel +Summary: Access control list static libraries and headers. +Group: Development/Libraries +Requires: libacl + +%description -n acl-devel +This package contains static libraries and header files needed to develop +programs which make use of the access control list programming interface +defined in POSIX 1003.1e draft standard 17. + +%prep +if [ -f .census ] ; then + if [ ! -d ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} ] ; then + ln -s . ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} + fi +else +%setup +touch .census +./configure +fi + +%build +@make@ + +%install +DIST_ROOT="$RPM_BUILD_ROOT" +DIST_INSTALL=`pwd`/install.manifest +DIST_INSTALL_DEV=`pwd`/install-dev.manifest +DIST_INSTALL_LIB=`pwd`/install-lib.manifest +export DIST_ROOT DIST_INSTALL DIST_INSTALL_DEV DIST_INSTALL_LIB +@make@ install DIST_MANIFEST="$DIST_INSTALL" +@make@ install-dev DIST_MANIFEST="$DIST_INSTALL_DEV" +@make@ install-lib DIST_MANIFEST="$DIST_INSTALL_LIB" +files() +{ + sort | uniq | awk ' +$1 == "d" { printf ("%%%%dir %%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $5); } +$1 == "f" { if (match ($6, "@pkg_man_dir@") || match ($6, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($6, "@pkg_man_dir@")) + printf ("%%%%attr(%s,%s,%s) %s*\n", $2, $3, $4, $6); + else + printf ("%%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $6); } +$1 == "l" { if (match ($3, "@pkg_man_dir@") || match ($3, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($3, "@pkg_man_dir@")) + printf ("%attr(0777,root,root) %s*\n", $3); + else + printf ("%attr(0777,root,root) %s\n", $3); }' +} +set +x +files < "$DIST_INSTALL" > files.rpm +files < "$DIST_INSTALL_DEV" > filesdevel.rpm +files < "$DIST_INSTALL_LIB" > fileslib.rpm +set -x + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -n libacl -p /sbin/ldconfig + +%postun -n libacl -p /sbin/ldconfig + +%files -f files.rpm + +%files -n acl-devel -f filesdevel.rpm + +%files -n libacl -f fileslib.rpm diff --git a/build/rpm/macros.template b/build/rpm/macros.template index e69de29..4557242 100644 --- a/build/rpm/macros.template +++ b/build/rpm/macros.template @@ -0,0 +1,31 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# Force 386 build on all platforms +# (why that?) +#%_target i386-pc-linux +#%_target_cpu i386 +#%_target_os linux + +# topdir == $(WORKAREA) +%_topdir %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In our case it's the same as $WORKAREA +%_builddir %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +# Be careful not to run full rpm build as it will override the sources +%_sourcedir %topdir%/build + +# This is where binary RPM and source RPM would end up +%_rpmdir %topdir%/build/rpm +%_srcrpmdir %topdir%/build/rpm +%_specdir %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +%_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm diff --git a/build/rpm/rpm-2.rc.template b/build/rpm/rpm-2.rc.template index e69de29..f3b3eba 100644 --- a/build/rpm/rpm-2.rc.template +++ b/build/rpm/rpm-2.rc.template @@ -0,0 +1,25 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# topdir == $(WORKAREA) +topdir: %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In out case it's the same as $WORKAREA +# Be careful not to run full rpm build as it will override the sources +builddir: %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +sourcedir: %topdir%/build + +# This is where binary RPM and source RPM would end up +rpmdir: %topdir%/build/rpm +srcrpmdir: %topdir%/build/rpm +specdir: %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +rpmfilename: %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm diff --git a/build/tar/Makefile b/build/tar/Makefile index e69de29..0a1be2b 100644 --- a/build/tar/Makefile +++ b/build/tar/Makefile @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +BINTAR=$(PKG_NAME)-$(PKG_VERSION).tar.gz +LDIRT = *.gz + +default install install-dev install-lib: + +include $(BUILDRULES) + +dist : default + @HERE=`pwd`; cd $${DIST_ROOT:-/}; \ + sort $$HERE/../bin-manifest | uniq | $(AWK) ' \ + $$1 == "f" { printf (".%s\n", $$6); } \ + $$1 == "d" { next; } \ + $$1 == "l" { printf (".%s\n", $$3); }' \ + | $(TAR) -T - -cf - | $(ZIP) --best > $$HERE/$(BINTAR) + @echo Wrote: `pwd`/$(BINTAR) diff --git a/configure.in b/configure.in index e69de29..1b957de 100644 --- a/configure.in +++ b/configure.in @@ -0,0 +1,199 @@ +dnl unpacking check - this file must exist +AC_INIT(include/sys/acl.h) +AC_CONFIG_HEADER(include/config.h) + +pkg_name="acl" +AC_SUBST(pkg_name) + +# +# Note: the following environment variables may be set to override the +# defaults (to change paths and/or executables, build parameters, etc): +# +# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO +# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX +# + +DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG +OPTIMIZER=${OPTIMIZER:-'-g'} # -O2 +MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a + +dnl Debug build? +debug_build="$DEBUG" +AC_SUBST(debug_build) + +dnl Optimization options? +opt_build="$OPTIMIZER" +AC_SUBST(opt_build) + +dnl Alternate malloc library? +malloc_lib="$MALLOCLIB" +AC_SUBST(malloc_lib) + +dnl Set version +. ./VERSION + +pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} +pkg_release=$PKG_BUILD +AC_SUBST(pkg_version) +AC_SUBST(pkg_release) + +dnl pkg_distribution="SGI XFS" +dnl test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" +dnl AC_SUBST(pkg_distribution) + +pkg_builder=`id -u -n`@`hostname` +test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER" +AC_SUBST(pkg_builder) + +dnl check if user wants their own C compiler +test -z "$CC" && AC_PROG_CC +cc=$CC +AC_SUBST(cc) + +dnl check if users wants their own make +test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make) +make=$MAKE +AC_SUBST(make) + +dnl check if users wants their own linker +test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld) +ld=$LD +AC_SUBST(ld) + +dnl check if the tar program is available +test -z "$TAR" && AC_PATH_PROG(TAR, tar) +tar=$TAR +AC_SUBST(tar) + +dnl check if the gzip program is available +test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip) +zip=$ZIP +AC_SUBST(zip) + +dnl check if the rpm program is available +test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm) +rpm=$RPM +AC_SUBST(rpm) + +dnl check if the msgfmt program is available +test -z "$MSGFMT" && AC_CHECK_PROG(MSGFMT, msgfmt, /usr/bin/msgfmt) +msgfmt=$MSGFMT +AC_SUBST(msgfmt) + +dnl .. and what version is rpm +rpm_version=0 +test -x $RPM && \ + rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'` +AC_SUBST(rpm_version) + +dnl check if the makedepend program is available +test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) +makedepend=$MAKEDEPEND +AC_SUBST(makedepend) + +dnl check if symbolic links are supported +AC_PROG_LN_S + +dnl check if user wants their own awk, sed and echo +test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk) +awk=$AWK +AC_SUBST(awk) +test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed) +sed=$SED +AC_SUBST(sed) +test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo) +echo=$ECHO +AC_SUBST(echo) + +dnl ensure libtool is installed +AC_PATH_PROG(LIBTOOL, libtool,,/usr/bin) +if test "$LIBTOOL" = ""; then + echo + echo 'FATAL ERROR: libtool does not seem to be installed.' + echo $pkg_name cannot be built without a working libtool installation. + exit 1 +fi +libtool=$LIBTOOL +AC_SUBST(libtool) + +dnl libtool to build libraries static only? +AC_ARG_ENABLE(shared, + [ --enable-shared=[yes/no] Enable use of shared libraries [default=yes].], + , + enable_shared=yes) +AC_SUBST(enable_shared) + +dnl alternate root and usr prefixes +test -z "$ROOT_PREFIX" && ROOT_PREFIX="" +root_prefix="$ROOT_PREFIX" +test -z "$PREFIX" && PREFIX="/usr" +prefix="$PREFIX" + +dnl man pages (source) +dnl also check if man page source is gzipped +dnl (usually on Debian, but not Redhat pre-7.0) +pkg_man_dir=${prefix}/share/man +have_zipped_manpages=false +for d in ${prefix}/share/man ${prefix}/man ; do + if test -f $d/man1/man.1.gz + then + pkg_man_dir=$d + have_zipped_manpages=true + break + fi +done +AC_SUBST(pkg_man_dir) +AC_SUBST(have_zipped_manpages) + +dnl binaries +pkg_bin_dir=${prefix}/bin +AC_SUBST(pkg_bin_dir) + +dnl static libraries +pkg_lib_dir=${prefix}/lib +AC_SUBST(pkg_lib_dir) + +dnl runtime shared system libraries +pkg_slib_dir=${root_prefix}/lib +AC_SUBST(pkg_slib_dir) + +dnl system binaries +pkg_sbin_dir=${root_prefix}/bin +AC_SUBST(pkg_sbin_dir) + +dnl include files +pkg_inc_dir=${prefix}/include +AC_SUBST(pkg_inc_dir) + +dnl doc directory +pkg_doc_dir=${prefix}/share/doc/${pkg_name} +AC_SUBST(pkg_doc_dir) + +dnl ... +AC_CHECK_HEADERS(attr/xattr.h) +if test "$ac_cv_header_attr_xattr_h" != "yes"; then + echo + echo 'FATAL ERROR: attr/xattr.h does not exist.' + echo $pkg_name cannot be built without the attr-devel package. + exit 1 +fi + +dnl machine characteristics +AC_C_BIGENDIAN +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) + +dnl GNU gettext +#ALL_LINGUAS="de" +#AM_GNU_GETTEXT + + +dnl +dnl output files +dnl + +AC_OUTPUT( \ +dnl Build definitions for use in Makefiles + include/builddefs \ +) diff --git a/doc/CHANGES b/doc/CHANGES index e69de29..412f963 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -0,0 +1,115 @@ +0.7.22 +* Create a shared version of libacl, instead of linking statically. +* Added missing error reporting to getfacl do_print() function. + +0.7.16 +* Minor cleanups/fixes in the make files +* The test cases in test/src have been updated to match the + corrected ACL entry syntax (see the 0.7.15 changes). + +0.7.15 +* acl_from_text() now accepts mask and other entries with either two + or three fields (`other:rwx' or `other::rwx'). Posix 1003.1e specifies + that these entries should have three entries, while under Solaris, + they have only two fields. +* setfacl now parses mask and other entries with two or three entries. +* getfacl now produces mask and other entries with three fields + (`mask::rwx' instead of the previous `mask:rwx'). +* acl_get_fd(), acl_get_file(), acl_set_fd(), acl_set_file() now only + fail with errno=ENOSYS if the underlying filesystem doesn't support + ACLs. acl_get_fd() and acl_get_file() construct ACLs from the file + mode permission bits if the kernel supports ACLs, but no ACL extended + attributes are defined for the file (errno=ENOATTR). +* acl_to_text() wrongly separated ACL entires with ',' instead of '\n'. +* acl_from_text() only accepted three-letter permission strings + (rwx, ---, rw-, etc.). Now also short strings (rw, -, etc.) are + supported. + +0.7.10 +* acl_get_fd(), acl_get_file() now don't return basic ACL's anymore. +* acl_set_fd(), acl_set_file() fail on filesystems that don't support + ACLs, even if the ACL to be set is a basice ACL. +* If msgfmt is not present on a system, the message catalog(s) are + no longer being built. + +0.7.8 (19 February 2001) +* Buffer overflow bug in ACL library (acl_to_any_text). + (Reported by Charles Bertsch <CBertsch@microtest.com>) + +0.7.2 (22 November 2000) +* Replace rman with groff for building HTML versions of the + manual pages. +* Add descriptions of the permissions required for manipulating + ACLs to the manual pages. +* Add long options to getfacl and setfacl, update the manual pages. +* Remove some small bugs from the src/showacl Perl script. +* showacl is now integrated in getfacl. +* Bug in acl_to_any_text() for ACLs with 0 entries fixed. +* Bug in acl_to_text(): Used '\n' as the ACL entry separator. +* German messages updated. + +0.7.1 (23 October 2000) +* Basic GNU gettext support and a German translation of messages + added. + +0.7.0 (22 October 2000) +* Updates to the documentation +* Now an ACL_MASK entry is cloned from the ACL_GROUP_OBJ entry + when needed also when the ACL_MASK entry is not re-calculated + (-n option), so setfacl doesn't complain about an invalid ACL. + +0.6.8 (11 October 2000) +* src/walk_tree.c was stat()ing the targets of symbolic links in + WALK_PHYSICAL mode. +* Removed spurious definitions from src/gettext.h that caused + problems with several versions of GNU gettext headers +* setfacl calls acl_delete_def_file() if removing the default ACL + of a directory that doesn't have a default ACL. i(If the user lacks + appropriate permissions, that no-operation fails.) Fixed. +* Tiny bug in src/showacl script (mask entry not applied to owning + group entry) + +0.6.5 (10 September 2000) +* Command line options revised for POSIX compatibility (now defaults to + -H half-logical walk, added -L logical walk, -P physical walk). +* Funny post-order option no longer documented. + +0.6.0 (24 March 2000) +* Permissions were not set to the union of the ACL_GROUP_OBJ and + ACL_MASK_OBJ entries for `setfacl -b'. +* getfacl didn't display the default ACL for links do directories. + +0.5.6 (31 Jan 2000) +* Cleaned up the ACL entry ring handling in the library +* Fixed a few minor issues with setfacl +* Fixed a bug in acl_equiv_mode +* Added acl_{get,set}_{file,fd}_mode functions + +0.5.5 (19 October 1999) +* Updates to the documentation +* Some other things (?) + +0.5.4 (up to 14 October 1999) +* Fixed an incompatibility with more recent GNU getopt +* Fixed a problem with errno handling in lib/text.c +* Some cosmetic changes to streamline the distribution process +* setfacl now implies `user:' if neither of `user', `group:', + `other:' and `mask:' is given. Was a major annoyance (to me). +* errno not set when acl_read was presented with an empty file. +* some missing '\n' chars in setfacl + +0.5.3 +* Fixed a bug in setfacl.c that caused the default mask to + be recalculated wrong. +* Fixed a bug in acl_kernel.c:acl_check_one() that caused + invalid ACLs to be accepted + +0.5.2 (25 September 1999) +* Added doc/Implementation.txt (some internals and ideas) +* Fixed a bug in lib/manip.c that caused setfacl to reject + some valid ACLs +* Fixed a bug that caused setfacl to produce duplicate ACL + entries +* Fixed a bug/feature that caused `sefacl -s' to include the + current base ACL entries in results. This is not done with + `setfacl -bm'. diff --git a/doc/CREDITS b/doc/CREDITS new file mode 100644 index 0000000..4f40005 --- /dev/null +++ b/doc/CREDITS @@ -0,0 +1,5 @@ +Thanks to Raymond S. Brand <rsbx@rsbx.net> for numerous improvements. + +Thanks to Dominik Kubla <dominik.kubla@uni-mainz.de> for adding the syscall +entry points for non-i386 architectures. + diff --git a/doc/LICENSE b/doc/LICENSE new file mode 100644 index 0000000..223ede7 --- /dev/null +++ b/doc/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/doc/Makefile b/doc/Makefile index e69de29..4f12302 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -0,0 +1,56 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = extensions.txt libacl.txt +#INSTALL PORTING CHANGES COPYING +LDIRT = *.gz + +default: CHANGES.gz + +include $(BUILDRULES) + +CHANGES.gz: + $(ZIP) --best -c < CHANGES > $@ + +install: default + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) + $(INSTALL) -m 644 PORTING CHANGES.gz $(PKG_DOC_DIR) +ifeq ($(PKG_DISTRIBUTION), debian) + $(INSTALL) -S CHANGES.gz $(PKG_DOC_DIR)/changelog.gz +else + $(INSTALL) -m 644 COPYING $(PKG_DOC_DIR) +endif + +install-dev install-lib: diff --git a/doc/PORTING b/doc/PORTING index e69de29..77829c6 100644 --- a/doc/PORTING +++ b/doc/PORTING @@ -0,0 +1,86 @@ + +1. unpack the source tarball and cd to the resulting dir + +2. # autoconf + this reads configure.in and generates the ./configure script + +3. # ./configure + this probes your system and then, for each "file" named + in the AC_OUTPUT() macro near the end of configure.in, + read "file".in and generate "file". Variables named @somevariable@ + will be substituted with literal values. + +4. step (3) produces several files. These files are generated by + configure from their respective .in file in the same directory. + You should have a read of these generated files and diff them + against their respective .in files to see what was substituted + by configure. + + src/include/builddefs + common definitions for the build environment. This is included + by all Makefiles, in conjunction with src/include/buildrules. + Note that most autoconf/configure build environments generate + Makefile (from Makefile.in) in every src dir. Instead, we + generate builddefs, and then include it in every Makefile. + + src/include/platform_defs.h + header containing conditional macros defining the C run-time + environment discovered by the configure script. + +5. read some or all of the GNU tool chain documentation + GNU make : + http://www.delorie.com/gnu/docs/make/make_toc.html + autoconf : + http://www.delorie.com/gnu/docs/autoconf/autoconf_toc.html + libtool : + http://www.delorie.com/gnu/docs/libtool/libtool_toc.html + gcc/g++ : + http://www.delorie.com/gnu/docs/gcc/gcc_toc.html + +6. Makefiles and build environment + First have a look at some Makefiles + + example using SUBDIRS : attr/Makefile + example static library: attr/libattr/Makefile + example command : attr/getfattr/Makefile + + All Makefiles must define TOPDIR as the root of the project. This + allows other stuff to be found relative to $(TOPDIR). + + All Makefiles should have the following structure, which is + much like commondefs and commonrules in the IRIX build environment, e.g. + + # ---------------------------------------------------------------------- + # TOPDIR must point to the root of the project + # The builddefs file defines lots of things. Read it. + TOPDIR = .. + include $(TOPDIR)/include/builddefs + + # first rule should always be "default" + default : sometarget + commands to build targets, if necessary + + # $(BUILDRULES) is defined in builddefs and includes rules for + # descending subdirs, building targets and installation rules + include $(BUILDRULES) + + install : default + $(INSTALL) sometargets somewhere + # ---------------------------------------------------------------------- + +7. packaging + + # ./Makepkgs + this script generates all of the packages supported - each has a + subdirectory below attr/build where knowledge specific to each + package type is maintained. + + The script produces logs of each stage of the build (this info is + also echoed to the screen when the "verbose" option is provided): + + attr/Logs/configure - `autoconf; ./configure' output + attr/Logs/default - `make default' output + attr/Logs/dist - `make build dist' output + + On successful completion, the script echoes the names of packages + successfully generated. diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..9c23d69 --- /dev/null +++ b/doc/TODO @@ -0,0 +1,4 @@ +- include po (gettext stuff) in packages and build process +- fix build process +- check documentation +- add manual pages for POSIX functions diff --git a/doc/extensions.txt b/doc/extensions.txt new file mode 100644 index 0000000..5455bbc --- /dev/null +++ b/doc/extensions.txt @@ -0,0 +1,77 @@ +The Posix ACL user library +========================== + +The Posix ACL manipulation functions defined in Posix 1003.1e DS17 are +declared in <sys/acl.h>; you need to link against libacl.a for these +functions to be included in your binaries. + +There is an additional header file <acl/libacl.h> that gives you +access to some extensions that are also contained in the same library. +The functions declared there are: + +acl_to_any_text() + + Similar to acl_to_text(), but also allows you to specify: + - a prefix string that is printed before each ACL entry. + - a seperator character that is printed between two ACL entries. + - a set of options (TEXT_* constants). + + This function returns the length in characters of the text returned + in the len_p parameter, unless len_p is NULL. The returned string + must be freed using the acl_free() function. + + Returns NULL and sets errno accordingly on error. + +acl_entry_to_any_str() + + Converts a single ACL entry to text, filling a buffer. It takes as + additional parameter the ACL mask entry (which is used to computer + the effective permissions if specified). The prefix and options are + the same as for acl_to_any_text(). + + Returns -1 and sets errno accordingly on error. + +acl_cmp() + + Returns 0 if both ACLs are equal, and 1 otherwise. + + Returns -1 and sets errno accordingly on error. + +acl_check() + + Checks an ACL for validity, similar to acl_valid. Returns the entry + at which an error occurred in last (unless last is NULL), and + returns a positive error code (ACL_*_ERROR) if the ACL is invalid; 0 + on success. + + Returns -1 and sets errno accordingly on error. + +acl_equiv_mode() + + Checks if an ACL is a basic ACL. If so, returns 0 and sets mode_p to + the file mode permission bits that correspond to the ACL. Returns 1 + otherwise. + + Returns -1 and sets errno accordingly on error. + +acl_entries() + + Returns the number of entries in an ACL. + + Returns -1 and sets errno accordingly on error. + +acl_error() + + Returns a textual message describing the error code returned by + acl_check(). + +acl_get_perm() + + Check if a permission is set in a permission set (acl_permset_t). + + Returns 1 if the permission is set, or 0 if it is not set. + Returns -1 and sets errno if an error occurs. + + +Andreas + diff --git a/doc/libacl.txt b/doc/libacl.txt new file mode 100644 index 0000000..bd5ef56 --- /dev/null +++ b/doc/libacl.txt @@ -0,0 +1,73 @@ +Internals of the libacl library +=============================== + +Posix 1003.1e DS17 leaves the library developer relatively few choices +on how to implement the library. A pseudo object oriented approach +seems necessary (otherwise, not all of the requirements can be met). +Unfortunately, C is no object oriented language, so the classes etc. +need to be hand coded. Here is how it works. + +From the user's point of view, the following things are objects: + + F - acl_t objects + - acl_entry_t objects + - acl_permset_t objects + F - strings returned by acl_to_text + F - entities returned by acl_get_qualifier + +The objects flagged with F need to be freed with acl_free() when they +are no longer needed. + +The user gets pointers to the contents of these objects. Each object +also has a prefix, which is not accessible from the user. The complete +objects are declared in <lib/libacl.h>. The p_magic field of the +prefix is set to <object_name>_MAGIC. + +The macros ext2int() and int2ext() convert between the internal and +external view on objects. The macros new_obj_p() and new_var_obj_p() +create a new object and object with variable size, respectively. See +the code for the rest. + +The code necessary to access fields in objects, especially in objects +accessed through indirections, would get almost unreadable. The second +ACL entry of an ACL would be: + + acl_obj *acl_p; + acl_entry_obj *acl_entry_p = acl_p->i.a_ring->i.e_next; + +For better readability, all the "i.a_", "i.e_" etc. parts can be +hidden using macros: + + acl_obj *acl_p; + acl_entry_obj *acl_entry_p = acl_p->aring->enext; + + +ACLs and ACL entries +==================== +The ACL entries associated with an ACL are stored on a sorted double +linked list. The first and last entries in that list are available via +ACL object. This is implemented with a little trick: + + The acl_obj and acl_entry_obj have {a,e}_prev and {a,e}_prev + pointers at the same memory location (directly after the object + prefix). The a_prev and a_next entries of an acl_obj are + initialized to point to the acl_obj itself (this requires a type + cast). We only need to check if the acl_obj object has been + reached to detect the end of the list. Since the acl_obj object + isn't actually an acl_entry_obj object, care must be taken not to + manipulate any of the other acl_entry_obj fields other than e_prev + and e_next. + +Whenever an entry is changed, __acl_reorder_obj_p() reorders the +entries accordingly. This takes O(n^2) time, but that's not a big +problem as long as ACLs don't contain very many entries. Some of the +library functions need a sorted ACL anyway, so the best we could +possibly do is O(n*log(n)), with a sorted flag in each ACL, and a +complicated sorting function (the linked list would have to be +converted to an array first to allow more efficient sorting). + + +Hope that helps. Good luck! + +Andreas + diff --git a/getfacl/Makefile b/getfacl/Makefile new file mode 100644 index 0000000..e882116 --- /dev/null +++ b/getfacl/Makefile @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LTCOMMAND = getfacl +CFILES = getfacl.c user_group.c + +LCFLAGS = -DPKG_NAME=\"$(PKG_NAME)\" -DLOCALEDIR=\"$(gnulocaledir)\" +LLDLIBS = -lattr $(LIBACL) +LTDEPENDENCIES = $(LIBACL) + +default: $(LTCOMMAND) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR) +install-dev install-lib: diff --git a/getfacl/getfacl.c b/getfacl/getfacl.c new file mode 100644 index 0000000..cc536cf --- /dev/null +++ b/getfacl/getfacl.c @@ -0,0 +1,737 @@ +/* + File: getfacl.c + (Linux Access Control List Management) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <sys/acl.h> +#include <acl/libacl.h> + +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/stat.h> +#include <dirent.h> +#include <ftw.h> +#include "user_group.h" + +//#define _GNU_SOURCE +#include <getopt.h> + +#include <locale.h> +#include <libintl.h> +#define _(String) gettext (String) + +#define POSIXLY_CORRECT_STR "POSIXLY_CORRECT" + +#if !POSIXLY_CORRECT +# define CMD_LINE_OPTIONS "adRLPvh" +#endif +#define POSIXLY_CMD_LINE_OPTIONS "dvh" + +struct option long_options[] = { +#if !POSIXLY_CORRECT + { "access", 0, 0, 'a' }, + { "omit-header", 0, 0, 'c' }, + { "all-effective", 0, 0, 'e' }, + { "no-effective", 0, 0, 'E' }, + { "skip-base", 0, 0, 's' }, + { "recursive", 0, 0, 'R' }, + { "logical", 0, 0, 'L' }, + { "physical", 0, 0, 'P' }, + { "tabular", 0, 0, 't' }, + { "absolute-names", 0, 0, 'p' }, +#endif + { "default", 0, 0, 'd' }, + { "version", 0, 0, 'v' }, + { "help", 0, 0, 'h' }, + { NULL, 0, 0, 0 } +}; + +const char *progname; +const char *cmd_line_options; + +int opt_recursive; /* recurse into sub-directories? */ +int opt_walk_logical; /* always follow symbolic links */ +int opt_walk_physical; /* never follow symbolic links */ +int opt_print_acl = 0; +int opt_print_default_acl = 0; +int opt_strip_leading_slash = 1; +int opt_comments = 1; /* include comments */ +int opt_skip_base = 0; /* skip files that only have the base entries */ +int opt_tabular = 0; /* tabular output format (alias `showacl') */ +#if POSIXLY_CORRECT +const int posixly_correct = 1; /* Posix compatible behavior! */ +#else +int posixly_correct = 0; /* Posix compatible behavior? */ +#endif +int had_errors = 0; +int absolute_warning = 0; /* Absolute path warning was issued */ +int print_options = TEXT_SOME_EFFECTIVE; + + +struct name_list { + struct name_list *next; + char name[0]; +}; + +void free_list(struct name_list *names) +{ + struct name_list *next; + + while (names) { + next = names->next; + free(names); + names = next; + } +} + +struct name_list *get_list(const struct stat *st, acl_t acl) +{ + struct name_list *first = NULL, *last = NULL; + const char *name; + acl_entry_t ent; + int len, ret = 0; + + if (acl != NULL) + ret = acl_get_entry(acl, ACL_FIRST_ENTRY, &ent); + if (ret != 1) + return NULL; + while (ret > 0) { + acl_tag_t e_type; + id_t *id_p; + + acl_get_tag_type(ent, &e_type); + switch(e_type) { + case ACL_USER_OBJ: + name = user_name(st->st_uid); + break; + + case ACL_USER: + name = NULL; + id_p = acl_get_qualifier(ent); + if (id_p != NULL) + name = user_name(*id_p); + break; + + case ACL_GROUP_OBJ: + name = group_name(st->st_gid); + break; + + case ACL_GROUP: + name = NULL; + id_p = acl_get_qualifier(ent); + if (id_p != NULL) + name = group_name(*id_p); + break; + + default: + name = NULL; + } + if (name == NULL) + name = ""; + len = strlen(name); + if (last == NULL) { + first = last = (struct name_list *) + malloc(sizeof(struct name_list) + len + 1); + } else { + last->next = (struct name_list *) + malloc(sizeof(struct name_list) + len + 1); + last = last->next; + } + if (last == NULL) { + free_list(first); + return NULL; + } + last->next = NULL; + strcpy(last->name, name); + + ret = acl_get_entry(acl, ACL_NEXT_ENTRY, &ent); + } + return first; +} + +int max_name_length(struct name_list *names) +{ + int max_len = 0; + while (names != NULL) { + struct name_list *next = names->next; + int len = strlen(names->name); + + if (len > max_len) + max_len = len; + names = next; + } + return max_len; +} + +int names_width; + +struct acl_perm_def { + acl_tag_t tag; + char c; +}; + +struct acl_perm_def acl_perm_defs[] = { + { ACL_READ, 'r' }, + { ACL_WRITE, 'w' }, + { ACL_EXECUTE, 'x' }, + { 0, 0 } +}; + +#define ACL_PERMS (sizeof(acl_perm_defs) / sizeof(struct acl_perm_def) - 1) + +void acl_perm_str(acl_entry_t entry, char *str) +{ + acl_permset_t permset; + int n; + + acl_get_permset(entry, &permset); + for (n = 0; n < (int) ACL_PERMS; n++) { + str[n] = (acl_get_perm(permset, acl_perm_defs[n].tag) ? + acl_perm_defs[n].c : '-'); + } + str[n] = '\0'; +} + +void acl_mask_perm_str(acl_t acl, char *str) +{ + acl_entry_t entry; + + str[0] = '\0'; + if (acl_get_entry(acl, ACL_FIRST_ENTRY, &entry) != 1) + return; + for(;;) { + acl_tag_t tag; + + acl_get_tag_type(entry, &tag); + if (tag == ACL_MASK) { + acl_perm_str(entry, str); + return; + } + if (acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) != 1) + return; + } +} + +void apply_mask(char *perm, const char *mask) +{ + while (*perm) { + if (*mask == '-' && *perm >= 'a' && *perm <= 'z') + *perm = *perm - 'a' + 'A'; + perm++; + if (*mask) + mask++; + } +} + +int show_line(FILE *stream, struct name_list **acl_names, acl_t acl, + acl_entry_t *acl_ent, const char *acl_mask, + struct name_list **dacl_names, acl_t dacl, + acl_entry_t *dacl_ent, const char *dacl_mask) +{ + acl_tag_t tag_type; + const char *tag, *name; + char acl_perm[ACL_PERMS+1], dacl_perm[ACL_PERMS+1]; + + if (acl) { + acl_get_tag_type(*acl_ent, &tag_type); + name = (*acl_names)->name; + } else { + acl_get_tag_type(*dacl_ent, &tag_type); + name = (*dacl_names)->name; + } + + switch(tag_type) { + case ACL_USER_OBJ: + tag = "USER"; + break; + case ACL_USER: + tag = "user"; + break; + case ACL_GROUP_OBJ: + tag = "GROUP"; + break; + case ACL_GROUP: + tag = "group"; + break; + case ACL_MASK: + tag = "mask"; + break; + case ACL_OTHER: + tag = "other"; + break; + default: + return -1; + } + + memset(acl_perm, ' ', ACL_PERMS); + acl_perm[ACL_PERMS] = '\0'; + if (acl_ent) { + acl_perm_str(*acl_ent, acl_perm); + if (tag_type != ACL_USER_OBJ && tag_type != ACL_OTHER && + tag_type != ACL_MASK) + apply_mask(acl_perm, acl_mask); + } + memset(dacl_perm, ' ', ACL_PERMS); + dacl_perm[ACL_PERMS] = '\0'; + if (dacl_ent) { + acl_perm_str(*dacl_ent, dacl_perm); + if (tag_type != ACL_USER_OBJ && tag_type != ACL_OTHER && + tag_type != ACL_MASK) + apply_mask(dacl_perm, dacl_mask); + } + + fprintf(stream, "%-5s %*s %*s %*s\n", + tag, -names_width, name, + -(int)ACL_PERMS, acl_perm, + -(int)ACL_PERMS, dacl_perm); + + if (acl_names) { + acl_get_entry(acl, ACL_NEXT_ENTRY, acl_ent); + (*acl_names) = (*acl_names)->next; + } + if (dacl_names) { + acl_get_entry(dacl, ACL_NEXT_ENTRY, dacl_ent); + (*dacl_names) = (*dacl_names)->next; + } + return 0; +} + +int do_show(FILE *stream, const char *path_p, const struct stat *st, + acl_t acl, acl_t dacl) +{ + struct name_list *acl_names = get_list(st, acl), + *first_acl_name = acl_names; + struct name_list *dacl_names = get_list(st, dacl), + *first_dacl_name = dacl_names; + + int acl_names_width = max_name_length(acl_names); + int dacl_names_width = max_name_length(dacl_names); + acl_entry_t acl_ent; + acl_entry_t dacl_ent; + char acl_mask[ACL_PERMS+1], dacl_mask[ACL_PERMS+1]; + int ret; + + names_width = 8; + if (acl_names_width > names_width) + names_width = acl_names_width; + if (dacl_names_width > names_width) + names_width = dacl_names_width; + + acl_mask[0] = '\0'; + if (acl) { + acl_mask_perm_str(acl, acl_mask); + ret = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_ent); + if (ret == 0) + acl = NULL; + if (ret < 0) + return ret; + } + dacl_mask[0] = '\0'; + if (dacl) { + acl_mask_perm_str(dacl, dacl_mask); + ret = acl_get_entry(dacl, ACL_FIRST_ENTRY, &dacl_ent); + if (ret == 0) + dacl = NULL; + if (ret < 0) + return ret; + } + fprintf(stream, "# file: %s\n", path_p); + while (acl_names != NULL || dacl_names != NULL) { + acl_tag_t acl_tag, dacl_tag; + + if (acl) + acl_get_tag_type(acl_ent, &acl_tag); + if (dacl) + acl_get_tag_type(dacl_ent, &dacl_tag); + + if (acl && (!dacl || acl_tag < dacl_tag)) { + show_line(stream, &acl_names, acl, &acl_ent, acl_mask, + NULL, NULL, NULL, NULL); + continue; + } else if (dacl && (!acl || dacl_tag < acl_tag)) { + show_line(stream, NULL, NULL, NULL, NULL, + &dacl_names, dacl, &dacl_ent, dacl_mask); + continue; + } else { + if (acl_tag == ACL_USER || acl_tag == ACL_GROUP) { + id_t *acl_id_p = NULL, *dacl_id_p = NULL; + if (acl_ent) + acl_id_p = acl_get_qualifier(acl_ent); + if (dacl_ent) + dacl_id_p = acl_get_qualifier(dacl_ent); + + if (acl && (!dacl || *acl_id_p < *dacl_id_p)) { + show_line(stream, &acl_names, acl, + &acl_ent, acl_mask, + NULL, NULL, NULL, NULL); + continue; + } else if (dacl && + (!acl || *dacl_id_p < *acl_id_p)) { + show_line(stream, NULL, NULL, NULL, + NULL, &dacl_names, dacl, + &dacl_ent, dacl_mask); + continue; + } + } + show_line(stream, &acl_names, acl, &acl_ent, acl_mask, + &dacl_names, dacl, &dacl_ent, dacl_mask); + } + } + + free_list(first_acl_name); + free_list(first_dacl_name); + + return 0; +} + +int do_print(const char *path_p, const struct stat *st) +{ + const char *str; + const char *default_prefix = NULL; + acl_t acl = NULL, default_acl = NULL; + int error = 0; + + if (opt_print_acl) { + acl = acl_get_file(path_p, ACL_TYPE_ACCESS); + if (acl == NULL && (errno == ENOSYS || errno == ENOTSUP)) + acl = acl_get_file_mode(path_p); + if (acl == NULL) + goto fail; + } + + if (opt_print_default_acl && S_ISDIR(st->st_mode)) { + default_acl = acl_get_file(path_p, ACL_TYPE_DEFAULT); + if (default_acl == NULL && errno != ENOSYS && errno != ENOTSUP) + goto fail; + if (acl_entries(default_acl) == 0) { + acl_free(default_acl); + default_acl = NULL; + } + } + + if (opt_skip_base && + (!acl || acl_equiv_mode(acl, NULL) == 0) && !default_acl) + return 0; + + if (opt_print_acl && opt_print_default_acl) + default_prefix = "default:"; + + if (opt_strip_leading_slash) { + if (*path_p == '/') { + if (!absolute_warning) { + fprintf(stderr, _("%s: Removing leading '/' " + "from absolute path names\n"), + progname); + absolute_warning = 1; + } + while (*path_p == '/') + path_p++; + } else if (*path_p == '.' && *(path_p+1) == '/') + while (*++path_p == '/') + /* nothing */ ; + if (*path_p == '\0') + path_p = "."; + } + + if (opt_tabular) { + if (do_show(stdout, path_p, st, acl, default_acl) != 0) + goto fail; + } else { + if (opt_comments) { + printf("# file: %s\n", path_p); + if ((str = user_name(st->st_uid)) != NULL) + printf("# owner: %s\n", str); + else + printf("# owner: %d\n", (int)st->st_uid); + if ((str = group_name(st->st_gid)) != NULL) + printf("# group: %s\n", str); + else + printf("# group: %d\n", (int)st->st_gid); + } + + if (acl != NULL && + acl_print(stdout, acl, NULL, print_options) < 0) + goto fail; + if (default_acl != NULL && + acl_print(stdout, default_acl, default_prefix, + print_options) < 0) + goto fail; + } + if (acl || default_acl || opt_comments) + printf("\n"); + +cleanup: + if (acl) + acl_free(acl); + if (default_acl) + acl_free(default_acl); + return error; + +fail: + fprintf(stderr, "%s: %s: %s\n", progname, path_p, strerror(errno)); + error = -1; + goto cleanup; +} + + +void help(void) +{ + printf(_("%s %s -- get file access control lists\n"), + progname, VERSION); + printf(_("Usage: %s [-%s] file ...\n"), + progname, cmd_line_options); +#if !POSIXLY_CORRECT + if (posixly_correct) { +#endif + printf(_( +" -d, --default display the default access control list\n")); +#if !POSIXLY_CORRECT + } else { + printf(_( +" -a, --access display the file access control list only\n" +" -d, --default display the default access control list only\n" +" --omit-header do not display the comment header\n" +" --all-effective print all effective rights\n" +" --no-effective print no effective rights\n" +" --skip-base skip files that only have the base entries\n" +" -R, --recursive recurse into subdirectories\n" +" --post-order visit subdirectories first\n" +" -L, --logical logical walk, follow symbolic links\n" +" -P --physical physical walk, do not follow symbolic links\n" +" --tabular use tabular output format\n" +" --absolute-names don't strip leading '/' in pathnames\n")); + } +#endif + printf(_( +" -v, --version print version and exit\n" +" -h, --help this help text\n")); +} + + +static int __errors; +int __do_print(const char *file, const struct stat *stat, + int flag, struct FTW *ftw) +{ + /* Process the target of a symbolic link, and traverse the link, + only if doing a logical walk, or if the symbolic link was + specified on the command line. Always skip symbolic links if + doing a physical walk. */ + + if (S_ISLNK(stat->st_mode) && + (opt_walk_physical || (ftw->level > 0 && !opt_walk_logical))) + return 0; + + if (do_print(file, stat)) + __errors++; + return 0; +} + +int walk_tree(const char *file) +{ + if (!opt_recursive) { + struct stat st; + + if (stat(file, &st)) { + fprintf(stderr, "%s: %s: %s\n", progname, file, + strerror(errno)); + return 1; + } + if (do_print(file, &st)) + return 1; + return 0; + } + + __errors = 0; + if (nftw(file, __do_print, 0, opt_recursive * FTW_PHYS)) { + fprintf(stderr, "%s: %s\n", progname, strerror(errno)); + __errors++; + } + return __errors; +} + +char *next_line(FILE *file) +{ + static char line[_POSIX_PATH_MAX], *c; + if (!fgets(line, sizeof(line), file)) + return NULL; + + c = strrchr(line, '\0'); + while (c > line && (*(c-1) == '\n' || + *(c-1) == '\r')) { + c--; + *c = '\0'; + } + return line; +} + + +int main(int argc, char *argv[]) +{ + int opt; + char *line; + + progname = argv[0]; + +#if POSIXLY_CORRECT + cmd_line_options = POSIXLY_CMD_LINE_OPTIONS; +#else + if (getenv(POSIXLY_CORRECT_STR)) + posixly_correct = 1; + if (!posixly_correct) + cmd_line_options = CMD_LINE_OPTIONS; + else + cmd_line_options = POSIXLY_CMD_LINE_OPTIONS; +#endif + + setlocale(LC_MESSAGES, ""); + bindtextdomain(PKG_NAME, LOCALEDIR); + textdomain(PKG_NAME); + + /* Align `#effective:' comments to column 40 for tty's */ + if (!posixly_correct && isatty(fileno(stdout))) + print_options |= TEXT_SMART_INDENT; + + while ((opt = getopt_long(argc, argv, cmd_line_options, + long_options, NULL)) != -1) { + switch (opt) { + case 'a': /* acl only */ + if (posixly_correct) + goto synopsis; + opt_print_acl = 1; + break; + + case 'd': /* default acl only */ + opt_print_default_acl = 1; + break; + + case 'c': /* no comments */ + if (posixly_correct) + goto synopsis; + opt_comments = 0; + break; + + case 'e': /* all #effective comments */ + if (posixly_correct) + goto synopsis; + print_options |= TEXT_ALL_EFFECTIVE; + break; + + case 'E': /* no #effective comments */ + if (posixly_correct) + goto synopsis; + print_options &= ~(TEXT_SOME_EFFECTIVE | + TEXT_ALL_EFFECTIVE); + break; + + case 'R': /* recursive */ + if (posixly_correct) + goto synopsis; + opt_recursive = 1; + break; + + case 'L': /* follow all symlinks */ + if (posixly_correct) + goto synopsis; + opt_walk_logical = 1; + opt_walk_physical = 0; + break; + + case 'P': /* skip all symlinks */ + if (posixly_correct) + goto synopsis; + opt_walk_logical = 0; + opt_walk_physical = 1; + break; + + case 's': /* skip files with only base entries */ + if (posixly_correct) + goto synopsis; + opt_skip_base = 1; + break; + + case 'p': + if (posixly_correct) + goto synopsis; + opt_strip_leading_slash = 0; + break; + + case 't': + if (posixly_correct) + goto synopsis; + opt_tabular = 1; + break; + + case 'v': /* print version */ + printf("%s " VERSION "\n", progname); + return 0; + + case 'h': /* help */ + help(); + return 0; + + case ':': /* option missing */ + case '?': /* unknown option */ + default: + goto synopsis; + } + } + + if (!(opt_print_acl || opt_print_default_acl)) { + opt_print_acl = 1; + if (!posixly_correct) + opt_print_default_acl = 1; + } + + if ((optind == argc) && !posixly_correct) + goto synopsis; + + do { + if (optind == argc || + strcmp(argv[optind], "-") == 0) { + while ((line = next_line(stdin)) != NULL) { + if (*line == '\0') + continue; + + had_errors += walk_tree(line); + } + if (ferror(stdin)) { + fprintf(stderr, _("%s: Standard input: %s\n"), + progname, strerror(errno)); + had_errors++; + } + } else + had_errors += walk_tree(argv[optind]); + optind++; + } while (optind < argc); + + return had_errors ? 1 : 0; + +synopsis: + fprintf(stderr, _("Usage: %s [-%s] file ...\n"), + progname, cmd_line_options); + fprintf(stderr, _("Try `%s -h' for more information.\n"), + progname); + return 2; +} + diff --git a/getfacl/showacl b/getfacl/showacl new file mode 100644 index 0000000..f6be88b --- /dev/null +++ b/getfacl/showacl @@ -0,0 +1,146 @@ +#!/usr/bin/perl -w +# +# Note that this script has been integrated into getfacl +# (--tabular option). +# + +use FileHandle; +use strict; + +my $pipe = new FileHandle("getfacl " . join (" ", map { s/\s/\\$&/g; $_; } @ARGV) . " |") + or die ($? >> 8); + +file: while (1) { + my ($file, $owner, $owning_group); + my $user = []; + my $group = []; + my $mask = undef; + my $other = []; + + while (my $line = <$pipe>) { + chomp $line; + if ($line =~ /^# (\w+): (.+)$/) { + $file = $2 + if ($1 eq 'file'); + $owner = $2 + if ($1 eq 'owner'); + $owning_group = $2 + if ($1 eq 'group'); + next; + } + $line =~ s/\s+#effective.*$//; + if ($line) { + my $fields = [ split /:/, $line ]; + if ($fields->[0] eq 'user') { + $fields->[0] =~ tr/a-z/A-Z/ + if $fields->[1] eq ''; + push @$user, $fields; + } elsif ($fields->[0] eq 'group') { + $fields->[0] =~ tr/a-z/A-Z/ + if $fields->[1] eq ''; + push @$group, $fields; + } elsif ($fields->[0] eq 'mask') { + $mask = [ $fields->[0], '', $fields->[1] ]; + } elsif ($fields->[0] eq 'other') { + $other = [ $fields->[0], '', $fields->[1] ]; + } elsif ($fields->[0] eq 'default') { + shift @$fields; + if ($fields->[0] eq 'user') { + add_default($user, $fields); + } elsif ($fields->[0] eq 'group') { + add_default($group, $fields); + } elsif ($fields->[0] eq 'mask') { + $mask = [ $fields->[0], '', '' ] + unless $mask; + push @$mask, $fields->[1]; + } elsif ($fields->[0] eq 'other') { + $other = [ $fields->[0], '', '' ] + unless $other; + push @$other, $fields->[1]; + } + } + } else { + $user->[0][1] = $owner; + $group->[0][1] = $owning_group; + for (my $i = 1; $i < @$user; $i++) { + $user->[$i][2] = + mask_perm($user->[$i][2], $mask->[2]); + $user->[$i][3] = + mask_perm($user->[$i][3], $mask->[3]) + if $user->[$i][3]; + } + for (my $i = 0; $i < @$group; $i++) { + $group->[$i][2] = + mask_perm($group->[$i][2], $mask->[2]); + $group->[$i][3] = + mask_perm($group->[$i][3], $mask->[3]) + if $group->[$i][3]; + } + + my $table = [ @$user, @$group ]; + push @$table, $mask + if @$mask; + push @$table, $other; + print "# file: $file\n"; + print_table($table, [5, 8, 3, 3]); + print "\n"; + next file; + } + } + last; +} + +close $pipe; + +sub add_default { + my ($list, $fields) = @_; + + for (my $i = 0; $i < @$list; $i++) { + if ($list->[$i][1] eq $fields->[1]) { + push @{$list->[$i]}, $fields->[2]; + return; + } + } + push @$list, [ $fields->[0], $fields->[1], '', $fields->[2] ]; +} + +sub print_table { + my ($table, $width) = @_; + for (my $i = 0; $i < @$table; $i++) { + my $row = $table->[$i]; + for (my $j = 0; $j < @$row; $j++) { + $width->[$j] = length $row->[$j] + unless ($width->[$j] && + $width->[$j] > length $row->[$j]); + } + } + my $fstr = ''; + for (my $j = 0; $j < @$width; $j++) { + $fstr .= "%-" . $width->[$j] . "s"; + if ($j + 1 < @$width) { + $fstr .= " "; + } else { + $fstr .= "\n"; + } + } + + for (my $i = 0; $i < @$table; $i++) { + print sprintf $fstr, @{$table->[$i]}; + } +} + +sub mask_perm { + my ($perm, $mask) = @_; + + return $perm unless $mask; + + my @p = split //, $perm; + my @m = split //, $mask; + for (my $i = 0; $i < @p; $i++) { + if ($p[$i] ne $m[$i]) { + $p[$i] = uc $p[$i]; + } + } + return join '', @p; +} + diff --git a/getfacl/user_group.c b/getfacl/user_group.c new file mode 100644 index 0000000..11f6867 --- /dev/null +++ b/getfacl/user_group.c @@ -0,0 +1,51 @@ +/* + File: user_group.c + (Linux Access Control List Management) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdlib.h> +#include "user_group.h" + + +const char * +user_name( + uid_t uid) +{ + struct passwd *passwd = getpwuid(uid); + + if (passwd != NULL) + return passwd->pw_name; + else + return NULL; +} + + +const char * +group_name( + gid_t gid) +{ + struct group *group = getgrgid(gid); + + if (group != NULL) + return group->gr_name; + else + return NULL; +} + diff --git a/getfacl/user_group.h b/getfacl/user_group.h new file mode 100644 index 0000000..8be04e6 --- /dev/null +++ b/getfacl/user_group.h @@ -0,0 +1,33 @@ +/* + File: user_group.h + (Linux Access Control List Management) + + Copyright (C) 1999 by Andreas Gruenbacher + <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> + +const char * +user_name( + uid_t uid); +const char * +group_name( + gid_t uid); + diff --git a/include/Makefile b/include/Makefile index e69de29..d62ec74 100644 --- a/include/Makefile +++ b/include/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +HFILES = sys/acl.h acl/libacl.h +LSRCFILES = builddefs.in buildrules acl_ea.h config.h.in + +default install install-lib: + +include $(BUILDRULES) + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_INC_DIR) + $(INSTALL) -m 755 -d $(PKG_INC_DIR)/sys + $(INSTALL) -m 755 -d $(PKG_INC_DIR)/acl + $(INSTALL) -m 644 sys/acl.h $(PKG_INC_DIR)/sys/acl.h + $(INSTALL) -m 644 acl/libacl.h $(PKG_INC_DIR)/acl/libacl.h diff --git a/include/acl/libacl.h b/include/acl/libacl.h new file mode 100644 index 0000000..f281110 --- /dev/null +++ b/include/acl/libacl.h @@ -0,0 +1,117 @@ +/* + File: libacl.h + + (C) 1999, 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org> +*/ + +#ifndef __ACL_LIBACL_H +#define __ACL_LIBACL_H + +#include <sys/acl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* acl_entry_to_any_str(), acl_to_any_text() */ + +/* Print NO, SOME or ALL effective permissions comments. SOME prints + effective rights comments for entries which have different permissions + than effective permissions. */ +#define TEXT_NO_EFFECTIVE 0x00 +#define TEXT_SOME_EFFECTIVE 0x01 +#define TEXT_ALL_EFFECTIVE 0x02 + +/* Align effective permission comments to column 32 using tabs or + use a single tab. */ +#define TEXT_SMART_INDENT 0x04 + +/* User and group IDs instead of names. */ +#define TEXT_NUMERIC_IDS 0x08 + +/* Only output the first letter of entry types + ("u::rwx" instead of "user::rwx"). */ +#define TEXT_ABBREVIATE 0x10 + +/* acl_check error codes */ + +#define ACL_MULTI_ERROR (0x1000) /* multiple unique objects */ +#define ACL_DUPLICATE_ERROR (0x2000) /* duplicate Id's in entries */ +#define ACL_MISS_ERROR (0x3000) /* missing required entry */ +#define ACL_ENTRY_ERROR (0x4000) /* wrong entry type */ + +extern char * +acl_to_any_text( + acl_t acl, + ssize_t *len_p, + const char *prefix, + char separator, + const char *suffix, + int options); +extern ssize_t +acl_entry_to_any_str( + const acl_entry_t entry_d, + char *text_p, + ssize_t size, + const acl_entry_t mask_d, + const char *prefix, + int options); +extern int +acl_cmp( + acl_t acl1, + acl_t acl2); +extern int +acl_check( + acl_t acl, + int *last); +extern acl_t +acl_from_mode( + mode_t mode); +extern int +acl_equiv_mode( + acl_t acl, + mode_t *mode_p); +extern acl_t +acl_get_file_mode( + const char *path_p); +extern acl_t +acl_get_fd_mode( + int fd); +extern int +acl_set_file_mode( + const char *path_p, + acl_type_t type, + acl_t acl); +extern int +acl_set_fd_mode( + int fd, + acl_t acl); +int +acl_extended_file( + const char *path_p); +int +acl_extended_fd( + int fd); +extern int +acl_print( + FILE *file, + acl_t acl, + const char *prefix, + int options); +extern int +acl_entries( + acl_t acl); +extern const char * +acl_error( + int code); +extern int +acl_get_perm( + acl_permset_t permset_d, + acl_perm_t perm); + +#ifdef __cplusplus +} +#endif + +#endif /* __ACL_LIBACL_H */ + diff --git a/include/acl_ea.h b/include/acl_ea.h new file mode 100644 index 0000000..cf36455 --- /dev/null +++ b/include/acl_ea.h @@ -0,0 +1,39 @@ +/* + File: acl_ea.h + + (extended attribute representation of access control lists) + + (C) 2002 Andreas Gruenbacher, <a.gruenbacher@computer.org> +*/ + +#define ACL_EA_ACCESS "system.posix_acl_access" +#define ACL_EA_DEFAULT "system.posix_acl_default" + +#define ACL_EA_VERSION 0x0002 + +typedef struct { + __u16 e_tag; + __u16 e_perm; + __u32 e_id; +} acl_ea_entry; + +typedef struct { + __u32 a_version; + acl_ea_entry a_entries[0]; +} acl_ea_header; + +static inline size_t acl_ea_size(int count) +{ + return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry); +} + +static inline int acl_ea_count(size_t size) +{ + if (size < sizeof(acl_ea_header)) + return -1; + size -= sizeof(acl_ea_header); + if (size % sizeof(acl_ea_entry)) + return -1; + return size / sizeof(acl_ea_entry); +} + diff --git a/include/builddefs.in b/include/builddefs.in index e69de29..eee4bb6 100644 --- a/include/builddefs.in +++ b/include/builddefs.in @@ -0,0 +1,222 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# @configure_input@ +# + +ifndef _BUILDDEFS_INCLUDED_ +_BUILDDEFS_INCLUDED_ = 1 + +DEBUG = @debug_build@ +OPTIMIZER = @opt_build@ +MALLOCLIB = @malloc_lib@ + +LIBACL = $(TOPDIR)/libacl/libacl.la + +PKG_NAME = @pkg_name@ +PKG_RELEASE = @pkg_release@ +PKG_VERSION = @pkg_version@ +PKG_DISTRIBUTION = @pkg_distribution@ +PKG_BUILDER = @pkg_builder@ +PKG_BIN_DIR = @pkg_bin_dir@ +PKG_LIB_DIR = @pkg_lib_dir@ +PKG_SBIN_DIR = @pkg_sbin_dir@ +PKG_SLIB_DIR = @pkg_slib_dir@ +PKG_INC_DIR = @pkg_inc_dir@ +PKG_MAN_DIR = @pkg_man_dir@ +PKG_DOC_DIR = @pkg_doc_dir@ + +CC = @cc@ +LD = @ld@ +AWK = @awk@ +SED = @sed@ +MAKE = @make@ +ECHO = @echo@ +LN_S = @LN_S@ +ZIP = @zip@ +TAR = @tar@ +RPM = @rpm@ +MSGFMT = @msgfmt@ + +RPM_VERSION = @rpm_version@ +HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ +MAKEDEPEND = @makedepend@ + +LIBTOOL = @LIBTOOL@ +ENABLE_SHARED = @enable_shared@ + +# +# end configure'd section + + +BUILDRULES = $(TOPDIR)/include/buildrules + +# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in +# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES) +# $(CXXFILES), or $(HFILES) and is used to construct the manifest list +# during the "dist" phase (packaging). + +CFLAGS += $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall -Wsign-compare \ + -D_GNU_SOURCE $(LCFLAGS) -I$(TOPDIR)/include \ + -DVERSION=\"$(PKG_VERSION)\" -D_FILE_OFFSET_BITS=64 + +LDFLAGS = $(LLDFLAGS) +LDLIBS = $(LLDLIBS) $(MALLOCLIB) + +MAKEOPTS = --no-print-directory +SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) +DIRT = $(LDIRT) $(OBJECTS) $(LTOBJECTS) *.[1-9].gz $(LTCOMMAND) $(LTLIBRARY) + +OBJECTS = $(ASFILES:.s=.o) \ + $(CFILES:.c=.o) \ + $(LFILES:.l=.o) \ + $(YFILES:%.y=%.tab.o) + +INSTALL = $(TOPDIR)/install-sh -o root -g root + +SHELL = /bin/sh +IMAGES_DIR = $(TOPDIR)/all-images +DIST_DIR = $(TOPDIR)/dist + +CCF = $(CC) $(CFLAGS) +MAKEF = $(MAKE) $(MAKEOPTS) +CXXF = $(CXX) $(CXXFLAGS) +LDF = $(LD) $(LDFLAGS) + +# For libtool. +LIBNAME = $(basename $(LTLIBRARY)) +LTOBJECTS = $(OBJECTS:.o=.lo) +LTVERSION = $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) + +LTLINK = $(LIBTOOL) --mode=link $(CC) +LTEXEC = $(LIBTOOL) --mode=execute +LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CCF) -D_REENTRANT -fno-strict-aliasing + +ifeq ($(ENABLE_SHARED),yes) +LTLDFLAGS += -rpath $(PKG_SLIB_DIR) +LTLDFLAGS += -version-info $(LTVERSION) +endif + +ifeq ($(ENABLE_SHARED),yes) +INSTALL_LTLIB = \ + cd $(TOPDIR)/$(LIBNAME)/.libs; \ + ../$(INSTALL) -m 755 -d $(PKG_SLIB_DIR); \ + ../$(INSTALL) -m 644 -T so_dot_version $(LIBNAME).lai $(PKG_SLIB_DIR); \ + test "$(PKG_DISTRIBUTION)" = debian || \ + ../$(INSTALL) -T so_dot_current $(LIBNAME).lai $(PKG_SLIB_DIR) +endif + +# Libtool thinks the static and shared libs should be in the same dir, so +# make the static lib appear in the place we chose as rpath (using the two +# symlinks below). +# Other things want the shared libs to appear in /usr/lib, else they'll +# link with the static libs there. So, another symlink to get the .so into +# /usr/lib. +ifeq ($(ENABLE_SHARED),yes) +INSTALL_LTLIB_DEV = \ + cd $(TOPDIR)/$(LIBNAME)/.libs; \ + ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \ + ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_LIB_DIR); \ + ../$(INSTALL) -m 644 $(LIBNAME).lai $(PKG_LIB_DIR)/$(LIBNAME).la ; \ + ../$(INSTALL) -m 755 -d $(PKG_SLIB_DIR); \ + ../$(INSTALL) -T so_base $(LIBNAME).lai $(PKG_SLIB_DIR); \ + ../$(INSTALL) -S $(PKG_LIB_DIR)/$(LIBNAME).a $(PKG_SLIB_DIR)/$(LIBNAME).a; \ + ../$(INSTALL) -S $(PKG_LIB_DIR)/$(LIBNAME).la $(PKG_SLIB_DIR)/$(LIBNAME).la; \ + ../$(INSTALL) -S $(PKG_SLIB_DIR)/$(LIBNAME).so $(PKG_LIB_DIR)/$(LIBNAME).so +else +INSTALL_LTLIB_DEV = $(INSTALL_LTLIB_STATIC) +endif + +INSTALL_LTLIB_STATIC = \ + cd $(TOPDIR)/$(LIBNAME)/.libs; \ + ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \ + ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_LIB_DIR) + +INSTALL_MAN = \ + @for d in $(MAN_PAGES); do \ + first=true; \ + for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \ + | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ + do \ + [ -z "$$m" -o "$$m" = "\\" ] && continue; \ + t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ + if $$first; then \ + if $(HAVE_ZIPPED_MANPAGES); then \ + $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \ + fi; \ + u=$$m.$(MAN_SECTION)$$_sfx; \ + echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + else \ + echo $(INSTALL) -S $$u $${t}$$_sfx; \ + $(INSTALL) -S $$u $${t}$$_sfx; \ + fi; \ + first=false; \ + done; \ + done + +SUBDIRS_MAKERULE = \ + @for d in $(SUBDIRS) ""; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(ECHO) === $$d ===; \ + $(MAKEF) -C $$d $@ || exit $$?; \ + fi; \ + done + +MAN_MAKERULE = \ + @for f in *.[12345678] ""; do \ + if test ! -z "$$f"; then \ + $(ZIP) --best -c < $$f > $$f.gz; \ + fi; \ + done + +DIST_MAKERULE = \ + $(MAKEF) -C build dist + +SOURCE_MAKERULE = \ + @test -z "$$DIR" && DIR="."; \ + for f in $(SRCFILES) ""; do \ + if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\ + done; \ + for d in `echo $(SUBDIRS)` ; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ + fi; \ + done + +endif + +# +# For targets that should always be rebuilt, +# define a target that is never up-to-date. +# Targets needing this should depend on $(_FORCE) +_FORCE = __force_build diff --git a/include/buildrules b/include/buildrules index e69de29..273643e 100644 --- a/include/buildrules +++ b/include/buildrules @@ -0,0 +1,81 @@ +# +# Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Fondation. +# +# This program is distributed in the hope that it would be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein, +# whether implied or otherwise, is limited to this program in accordance with +# the express provisions of the GNU General Public License. Patent licenses, +# if any, provided herein do not apply to combinations of this program with +# other product or programs, or any other product whatsoever. This program is +# distributed without any warranty that the program is delivered free of the +# rightful claim of any third person by way of infringement or the like. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston MA 02111-1307, USA. +# Common build rules for gmake +# +ifndef _BUILDRULES_INCLUDED_ +_BUILDRULES_INCLUDED_ = 1 + +include $(TOPDIR)/include/builddefs + +clean clobber : $(SUBDIRS) + rm -f $(DIRT) + @rm -fr .libs + $(SUBDIRS_MAKERULE) + +# Never blow away subdirs +ifdef SUBDIRS +.PRECIOUS: $(SUBDIRS) +$(SUBDIRS): + $(SUBDIRS_MAKERULE) +endif + +# +# Standard targets +# + +ifdef LTCOMMAND +$(LTCOMMAND) : $(SUBDIRS) $(OBJECTS) $(LTDEPENDENCIES) + $(LTLINK) -o $@ $(LDFLAGS) $(OBJECTS) $(LDLIBS) +endif + +ifdef LTLIBRARY +$(LTLIBRARY) : $(SUBDIRS) $(LTOBJECTS) + $(LTLINK) $(LTLDFLAGS) -o $(LTLIBRARY) $(LTOBJECTS) $(LTLIBS) + +%.lo: %.c + $(LTCOMPILE) -c $< +endif + +source : + $(SOURCE_MAKERULE) + +endif # _BUILDRULES_INCLUDED_ + +$(_FORCE): + +.PHONY : depend + +depend : $(CFILES) $(HFILES) + $(SUBDIRS_MAKERULE) + touch .dep + $(MAKEDEPEND) -f - -- $(CFLAGS) -- $(CFILES) | \ + sed -e 's,`pwd`,$(TOPDIR),g' \ + -e 's, */[^ ]*,,g' \ + -e '/^[^ ]*: *$$/d' \ + -e '/^#.*/d' -e '/^ *$$/d' \ + > .dep + test -s .dep || rm -f .dep + +# Include dep, but only if it exists +ifeq ($(shell test -f .dep && echo .dep), .dep) +include .dep +endif diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..1cd2b8c --- /dev/null +++ b/include/config.h @@ -0,0 +1,17 @@ +/* include/config.h. Generated automatically by configure. */ +/* Define if you want Posix compliant getfacl and setfacl utilities + without extensions */ +/* #undef POSIXLY_CORRECT */ + +/* The number of bytes in a int. */ +#define SIZEOF_INT 4 + +/* The number of bytes in a long. */ +#define SIZEOF_LONG 4 + +/* The number of bytes in a short. */ +#define SIZEOF_SHORT 2 + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ diff --git a/include/config.h.in b/include/config.h.in new file mode 100644 index 0000000..90fa954 --- /dev/null +++ b/include/config.h.in @@ -0,0 +1,16 @@ +/* Define if you want Posix compliant getfacl and setfacl utilities + without extensions */ +#undef POSIXLY_CORRECT + +/* The number of bytes in a int. */ +#undef SIZEOF_INT + +/* The number of bytes in a long. */ +#undef SIZEOF_LONG + +/* The number of bytes in a short. */ +#undef SIZEOF_SHORT + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN diff --git a/include/sys/acl.h b/include/sys/acl.h new file mode 100644 index 0000000..e34d470 --- /dev/null +++ b/include/sys/acl.h @@ -0,0 +1,204 @@ +/* + File: sys/acl.h + + (C) 1999 Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __SYS_ACL_H +#define __SYS_ACL_H + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*=== Data types ===*/ + +struct __acl_ext; +struct __acl_entry_ext; +struct __acl_permset_ext; + +typedef unsigned int acl_type_t; +typedef int acl_tag_t; +typedef unsigned int acl_perm_t; + +typedef struct __acl_ext *acl_t; +typedef struct __acl_entry_ext *acl_entry_t; +typedef struct __acl_permset_ext *acl_permset_t; + +/*=== Constants ===*/ + +/* 23.2.2 acl_perm_t values */ + +#define ACL_READ (0x04) +#define ACL_WRITE (0x02) +#define ACL_EXECUTE (0x01) +//#define ACL_ADD (0x08) +//#define ACL_DELETE (0x10) + +/* 23.2.5 acl_tag_t values */ + +#define ACL_UNDEFINED_TAG (0x00) +#define ACL_USER_OBJ (0x01) +#define ACL_USER (0x02) +#define ACL_GROUP_OBJ (0x04) +#define ACL_GROUP (0x08) +#define ACL_MASK (0x10) +#define ACL_OTHER (0x20) + +/* 23.3.6 acl_type_t values */ + +#define ACL_TYPE_ACCESS (0x8000) +#define ACL_TYPE_DEFAULT (0x4000) + +/* 23.2.7 ACL qualifier constants */ + +#define ACL_UNDEFINED_ID ((unsigned int)-1) + +/* 23.2.8 ACL Entry Constants */ + +#define ACL_FIRST_ENTRY 0 +#define ACL_NEXT_ENTRY 1 + +/*=== ACL manipulation ===*/ + +extern acl_t +acl_init( + int count); +extern acl_t +acl_dup( + acl_t acl); +extern int +acl_free( + void *obj_p); +extern int +acl_valid( + acl_t acl); + +/*=== Entry manipulation ===*/ + +extern int +acl_copy_entry( + acl_entry_t dest_d, + acl_entry_t src_d); +extern int +acl_create_entry( + acl_t *acl_p, + acl_entry_t *entry_p); +extern int +acl_delete_entry( + acl_t acl, + acl_entry_t entry_d); +extern int +acl_get_entry( + acl_t acl, + int entry_id, + acl_entry_t *entry_p); + +/* Manipulate ACL entry permissions */ + +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_delete_perm( + acl_permset_t permset_d, + acl_perm_t perm); +extern int +acl_get_permset( + acl_entry_t entry_d, + acl_permset_t *permset_p); +extern int +acl_set_permset( + acl_entry_t entry_d, + acl_permset_t permset_d); + +/* Manipulate ACL entry tag type and qualifier */ + +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 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); + +/*=== Format translation ===*/ + +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 acl_t +acl_from_text( + const char *buf_p); +extern ssize_t +acl_size( + acl_t acl); +extern char * +acl_to_text( + acl_t acl, + ssize_t *len_p); + +/*=== Object manipulation ===*/ + +extern int +acl_delete_def_file( + const char *path_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_set_fd( + int fd, + acl_t acl); +extern int +acl_set_file( + const char *path_p, + acl_type_t type, + acl_t acl); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYS_ACL_H */ + @@ -0,0 +1,381 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# This script emulates bsd install and also recognises +# two environment variables, with the following semantics :- +# +# $DIST_MANIFEST - if set, the name of the file to append manifest +# information in the following format: +# File : f mode owner group src target +# Directory: d mode owner group target +# Symlink : l linkval target +# +# $DIST_ROOT - if set, prepend to target +# +# The sematics of all combinations of these two variables +# are as follows: +# +# $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? +# -----------------------------+-------------------------- +# not set not set | yes no +# not set set | yes no +# set not set | no yes +# set set | yes yes +# +_usage() { + echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" + echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" + echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" + echo "or $prog -S file target (creates \"target\" symlink)" + echo "or $prog -T lt_arg [-o owner] [-g group] [-m mode] libtool.lai directory" + echo "" + echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" + echo "behaviour of this command - see comments in the script." + echo "The -D flag is only available for the second usage, and causes" + echo "the target directory to be created before installing the file." + echo "" + exit 1 +} + +_chown () +{ + _st=255 + if [ $# -eq 3 ] ; then + chown $1:$2 $3 + _st=$? + if [ $_st -ne 0 ] ; then + if [ $REAL_UID != '0' ] ; then + if [ ! -f $DIST_ROOT/.chown.quiet ] ; then + echo '===============================================' + echo Ownership of files under ${DIST_ROOT:-/} + echo cannot be changed + echo '===============================================' + if [ -n "$DIST_ROOT" ] ; then + touch $DIST_ROOT/.chown.quiet + fi + fi + _st=0 + fi + fi + fi + + return $_st +} + + +_manifest () +{ + echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} +} + +prog=`basename $0` +HERE=`pwd` +dflag=false +Dflag=false +Sflag=false +Tflag=false +DIRMODE=755 +FILEMODE=644 +OWNER=`id -u` +GROUP=`id -g` +REAL_UID=$OWNER + +# default is to install and don't append manifest +INSTALL=true +MANIFEST=: + +[ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false +[ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" + +[ $# -eq 0 ] && _usage + +if $INSTALL +then + CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown +else + CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true +fi + +[ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true + +while getopts "Dcm:d:S:o:g:T:" c $* +do + case $c in + c) + ;; + g) + GROUP=$OPTARG + ;; + o) + OWNER=$OPTARG + ;; + m) + DIRMODE=`expr $OPTARG` + FILEMODE=$DIRMODE + ;; + D) + Dflag=true + ;; + S) + symlink=$OPTARG + Sflag=true + ;; + d) + dir=$DIST_ROOT/$OPTARG + dflag=true + ;; + T) + lt_install=$OPTARG + Tflag=true + ;; + *) + _usage + ;; + esac +done + +shift `expr $OPTIND - 1` + +status=0 +if $dflag +then + # + # first usage + # + $MKDIR -p $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $DIRMODE $dir + status=$? + fi + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} +elif $Sflag +then + # + # fourth usage (symlink) + # + if [ $# -ne 1 ] + then + _usage + else + target=$DIST_ROOT/$1 + fi + $LN -s -f $symlink $target + status=$? + $MANIFEST l $symlink ${target#$DIST_ROOT} +elif $Tflag +then + # + # -T (install libs built by libtool) + # + if [ $# -ne 2 ] + then + _usage + else + libtool_lai=$1 + # source the libtool variables + if [ ! -f $libtool_lai ] + then + echo "$prog: Unable to find libtool library file $libtool_lai" + exit 2 + fi + . ./$libtool_lai + target=$DIST_ROOT/$2 + fi + case $lt_install in + so_dot_version) + # Loop until we find libfoo.so.x.y.z, then break out. + for solib in $library_names + do + # does it have enough parts? libfoo.so.x.y.z == 5 + cnt=`echo "$solib" | sed -e 's/\./ /g' | wc -w` + if [ $cnt -eq 5 ] + then + install_name=$target/$solib + $CP $solib $install_name + status=$? + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$solib ${install_name#$DIST_ROOT} + break + fi + done + ;; + + so_*) + case $lt_install in + so_dot_current) + # ln -s libfoo.so.x.y.z to libfoo.so.x + from_parts=5 # libfoo.so.x.y.z + to_parts=3 # libfoo.so.x + ;; + so_base) + # ln -s libfoo.so.x to libfoo.so + from_parts=3 # libfoo.so.x + to_parts=2 # libfoo.so + ;; + *) + echo "$prog: -T $lt_install invalid" + exit 2 + ;; + esac + + # Loop until we find the names, then break out. + for solib in $library_names + do + # does it have enough parts? + cnt=`echo "$solib" | sed -e 's/\./ /g' | wc -w` + if [ $cnt -eq $from_parts ] + then + from_name=$solib + elif [ $cnt -eq $to_parts ] + then + to_name=$solib + fi + + if [ -n "$from_name" ] && [ -n "$to_name" ] + then + install_name=$target/$to_name + $LN -s -f $from_name $install_name + status=$? + $MANIFEST l $from_name ${install_name#$DIST_ROOT} + break + fi + done + ;; + old_lib) + install_name=$target/$old_library + $CP $old_library $install_name + status=$? + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$old_library ${install_name#$DIST_ROOT} + ;; + *) + echo "$prog: -T $lt_install invalid" + exit 2 + ;; + esac + + case $lt_install in + old_lib|so_dot_version) + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $install_name + $CHOWN $OWNER $GROUP $install_name + fi + ;; + esac + +else + list="" + dir="" + if [ $# -eq 2 ] + then + # + # second usage + # + f=$1 + dir=$DIST_ROOT/$2 + if $Dflag + then + mkdir -p `dirname $dir` + fi + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + if [ -f $dir/$f ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + else + $CHMOD $FILEMODE $dir + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} + fi + fi + else + # + # third usage + # + n=1 + while [ $# -gt 0 ] + do + if [ $# -gt 1 ] + then + list="$list $1" + else + dir=$DIST_ROOT/$1 + fi + shift + done + + echo DIR=$dir list=\"$list\" + for f in $list + do + $CP $f $dir + status=$? + # from/file.x -> $dir/file.x, not $dir/from/file.x + f=`basename $f` + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + fi + [ $status -ne 0 ] && break + done + fi +fi + +exit $status diff --git a/libacl/Makefile b/libacl/Makefile index e69de29..30ce85b 100644 --- a/libacl/Makefile +++ b/libacl/Makefile @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, +# USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LTLIBRARY = libacl.la +LTLIBS = -lattr +LT_CURRENT = 1 +LT_REVISION = 0 +LT_AGE = 0 + +CFILES = $(POSIX_CFILES) $(LIBACL_CFILES) $(INTERNAL_CFILES) +HFILES = libobj.h libacl.h + +POSIX_CFILES = \ + acl_add_perm.c acl_calc_mask.c acl_clear_perms.c acl_copy_entry.c \ + acl_copy_ext.c acl_copy_int.c acl_create_entry.c acl_delete_def_file.c \ + acl_delete_entry.c acl_delete_perm.c acl_dup.c acl_free.c \ + acl_from_text.c acl_get_entry.c acl_get_fd.c acl_get_file.c \ + acl_get_perm.c acl_get_permset.c acl_get_qualifier.c \ + acl_get_tag_type.c acl_init.c acl_print.c acl_set_fd.c acl_set_file.c \ + acl_set_permset.c acl_set_qualifier.c acl_set_tag_type.c acl_to_text.c \ + acl_valid.c + +LIBACL_CFILES = \ + acl_check.c acl_cmp.c acl_entries.c acl_entry_to_any_str.c \ + acl_equiv_mode.c acl_error.c acl_extended_fd.c acl_extended_file.c \ + acl_from_mode.c acl_get_fd_mode.c acl_get_file_mode.c \ + acl_set_fd_mode.c acl_set_file_mode.c acl_size.c acl_to_any_text.c + +INTERNAL_CFILES = \ + __acl_to_xattr.c __acl_from_xattr.c __acl_reorder_obj_p.c __libobj.c + + +default: $(LTLIBRARY) + +include $(BUILDRULES) + +install: + +install-dev: default + $(INSTALL_LTLIB_DEV) + +install-lib: default + $(INSTALL_LTLIB) diff --git a/libacl/__acl_from_xattr.c b/libacl/__acl_from_xattr.c new file mode 100644 index 0000000..65ef5dc --- /dev/null +++ b/libacl/__acl_from_xattr.c @@ -0,0 +1,95 @@ +/* + File: __acl_from_xattr.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +acl_t +__acl_from_xattr( + const char *ext_acl_p, + size_t size) +{ + acl_ea_header *ext_header_p = (acl_ea_header *)ext_acl_p; + acl_ea_entry *ext_entry_p = (acl_ea_entry *)(ext_header_p+1); + acl_ea_entry *ext_end_p; + acl_obj *acl_obj_p; + acl_entry_obj *entry_obj_p; + int error; + + if (size < sizeof(acl_ea_header)) { + errno = EINVAL; + return NULL; + } + if (ext_header_p->a_version != cpu_to_le32(ACL_EA_VERSION)) { + errno = EINVAL; + return NULL; + } + size -= sizeof(acl_ea_header); + if (size % sizeof(acl_ea_entry)) { + errno = EINVAL; + return NULL; + } + ext_end_p = ext_entry_p + (size / sizeof(acl_ea_entry)); + + acl_obj_p = __acl_init_obj(); + if (acl_obj_p == NULL) + return NULL; + while (ext_end_p != ext_entry_p) { + entry_obj_p = __acl_create_entry_obj(acl_obj_p); + if (!entry_obj_p) + goto fail; + + entry_obj_p->etag = le16_to_cpu(ext_entry_p->e_tag); + entry_obj_p->eperm.sperm = le16_to_cpu(ext_entry_p->e_perm); + + switch(entry_obj_p->etag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + entry_obj_p->eid.qid = ACL_UNDEFINED_ID; + break; + + case ACL_USER: + case ACL_GROUP: + entry_obj_p->eid.qid = + le32_to_cpu(ext_entry_p->e_id); + break; + + default: + error = EINVAL; + goto fail; + } + /* we keep the ACL entries permanently ordered. */ + __acl_reorder_obj_p(entry_obj_p); + + ext_entry_p++; + } + return int2ext(acl_obj_p); + +fail: + __acl_free_acl_obj(acl_obj_p); + return NULL; +} + diff --git a/libacl/__acl_from_xattr.h b/libacl/__acl_from_xattr.h new file mode 100644 index 0000000..4492a34 --- /dev/null +++ b/libacl/__acl_from_xattr.h @@ -0,0 +1 @@ +acl_t __acl_from_xattr(const char *ext_acl_p, size_t size); diff --git a/libacl/__acl_reorder_obj_p.c b/libacl/__acl_reorder_obj_p.c new file mode 100644 index 0000000..d5b420a --- /dev/null +++ b/libacl/__acl_reorder_obj_p.c @@ -0,0 +1,87 @@ +/* + File: __acl_reorder_obj_p.c + (Linux Access Control List Management, Posix Library Functions) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +static inline int +__acl_entry_compare( + acl_entry_obj *a_p, + acl_entry_obj *b_p) +{ + if (a_p->etag < b_p->etag) + return -1; + else if (a_p->etag > b_p->etag) + return 1; + + if (a_p->eid.qid < b_p->eid.qid) + return -1; + else if (a_p->eid.qid > b_p->eid.qid) + return 1; + else + return 0; +} + + +/* + Take an ACL entry form its current place in the entry ring, + and insert it at its proper place. Entries that are not valid + (yet) are not reordered. +*/ +int +__acl_reorder_obj_p( + acl_entry_obj *entry_obj_p) +{ + acl_obj *acl_obj_p = entry_obj_p->econtainer; + acl_entry_obj *here_obj_p; + + if (acl_obj_p->aused <= 1) + return 0; + switch(entry_obj_p->etag) { + case ACL_UNDEFINED_TAG: + return 1; + case ACL_USER: + case ACL_GROUP: + if (qualifier_obj_id(entry_obj_p->eid) == + ACL_UNDEFINED_ID) + return 1; + } + + /* Remove entry from ring */ + entry_obj_p->eprev->enext = entry_obj_p->enext; + entry_obj_p->enext->eprev = entry_obj_p->eprev; + + /* Search for next greater entry */ + FOREACH_ACL_ENTRY(here_obj_p, acl_obj_p) { + if (__acl_entry_compare(here_obj_p, entry_obj_p) > 0) + break; + } + + /* Re-insert entry into ring */ + entry_obj_p->eprev = here_obj_p->eprev; + entry_obj_p->enext = here_obj_p; + entry_obj_p->eprev->enext = entry_obj_p; + entry_obj_p->enext->eprev = entry_obj_p; + + return 0; +} + diff --git a/libacl/__acl_to_xattr.c b/libacl/__acl_to_xattr.c new file mode 100644 index 0000000..744a52e --- /dev/null +++ b/libacl/__acl_to_xattr.c @@ -0,0 +1,65 @@ +/* + File: __acl_to_xattr.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <errno.h> +#include <sys/acl.h> +#include "libacl.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +char * +__acl_to_xattr( + const acl_obj *acl_obj_p, + size_t *size) +{ + const acl_entry_obj *entry_obj_p; + acl_ea_header *ext_header_p; + acl_ea_entry *ext_ent_p; + + *size = sizeof(acl_ea_header) + acl_obj_p->aused * sizeof(acl_ea_entry); + ext_header_p = (acl_ea_header *)malloc(*size); + if (!ext_header_p) + return NULL; + + ext_header_p->a_version = cpu_to_le32(ACL_EA_VERSION); + ext_ent_p = (acl_ea_entry *)(ext_header_p+1); + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + ext_ent_p->e_tag = cpu_to_le16(entry_obj_p->etag); + ext_ent_p->e_perm = cpu_to_le16(entry_obj_p->eperm.sperm); + + switch(entry_obj_p->etag) { + case ACL_USER: + case ACL_GROUP: + ext_ent_p->e_id = + cpu_to_le32(entry_obj_p->eid.qid); + break; + + default: + ext_ent_p->e_id = ACL_UNDEFINED_ID; + break; + } + ext_ent_p++; + } + return (char *)ext_header_p; +} + diff --git a/libacl/__acl_to_xattr.h b/libacl/__acl_to_xattr.h new file mode 100644 index 0000000..e880550 --- /dev/null +++ b/libacl/__acl_to_xattr.h @@ -0,0 +1 @@ +char * __acl_to_xattr(const acl_obj *acl_obj_p, size_t *size); diff --git a/libacl/__libobj.c b/libacl/__libobj.c new file mode 100644 index 0000000..12cfb3a --- /dev/null +++ b/libacl/__libobj.c @@ -0,0 +1,59 @@ +#include <errno.h> +#include <stdlib.h> +#include "libobj.h" + +#ifdef LIBACL_DEBUG +# include <stdio.h> +#endif + +/* object creation, destruction, conversion and validation */ + +void * +__new_obj_p(int magic, size_t size) +{ + obj_prefix *obj_p = (obj_prefix *)malloc(size); + if (obj_p) + obj_p->p_magic = magic; + return obj_p; +} + + +void +__free_obj_p(obj_prefix *obj_p) +{ + obj_p->p_magic = 0; + free(obj_p); +} + + +obj_prefix * +__check_obj_p(obj_prefix *obj_p, int magic) +{ + if (!obj_p || obj_p->p_magic != magic) { + errno = EINVAL; + return NULL; + } + return obj_p; +} + + +#ifdef LIBACL_DEBUG +obj_prefix * +__ext2int_and_check(void *ext_p, int magic, const char *typename) +#else +obj_prefix * +__ext2int_and_check(void *ext_p, int magic) +#endif +{ + obj_prefix *obj_p = ((obj_prefix *)ext_p)-1; + if (!ext_p) { +#ifdef LIBACL_DEBUG + fprintf(stderr, "invalid %s object at %p\n", + typename, obj_p); +#endif + errno = EINVAL; + return NULL; + } + return __check_obj_p(obj_p, magic); +} + diff --git a/libacl/acl_add_perm.c b/libacl/acl_add_perm.c new file mode 100644 index 0000000..f7461aa --- /dev/null +++ b/libacl/acl_add_perm.c @@ -0,0 +1,37 @@ +/* + File: acl_add_perm.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.1 */ +int +acl_add_perm( + acl_permset_t permset_d, + acl_perm_t perm) +{ + acl_permset_obj *acl_permset_obj_p = ext2int(acl_permset, permset_d); + if (!acl_permset_obj_p || (perm & !(ACL_READ|ACL_WRITE|ACL_EXECUTE))) + return -1; + acl_permset_obj_p->sperm |= perm; + return 0; +} + diff --git a/libacl/acl_calc_mask.c b/libacl/acl_calc_mask.c new file mode 100644 index 0000000..74c6d74 --- /dev/null +++ b/libacl/acl_calc_mask.c @@ -0,0 +1,68 @@ +/* + File: acl_calc_mask.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.2 */ +int +acl_calc_mask( + acl_t *acl_p) +{ + acl_obj *acl_obj_p; + acl_entry_obj *entry_obj_p, *mask_obj_p = NULL; + permset_t perm = ACL_PERM_NONE; + if (!acl_p) { + errno = EINVAL; + return -1; + } + acl_obj_p = ext2int(acl, *acl_p); + if (!acl_obj_p) + return -1; + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + switch(entry_obj_p->etag) { + case ACL_USER_OBJ: + case ACL_OTHER: + break; + case ACL_MASK: + mask_obj_p = entry_obj_p; + break; + case ACL_USER: + case ACL_GROUP_OBJ: + case ACL_GROUP: + perm |= entry_obj_p->eperm.sperm; + break; + default: + errno = EINVAL; + return -1; + } + } + if (mask_obj_p == NULL) { + mask_obj_p = __acl_create_entry_obj(acl_obj_p); + if (mask_obj_p == NULL) + return -1; + mask_obj_p->etag = ACL_MASK; + __acl_reorder_obj_p(mask_obj_p); + } + mask_obj_p->eperm.sperm = perm; + return 0; +} + diff --git a/libacl/acl_check.c b/libacl/acl_check.c new file mode 100644 index 0000000..635005d --- /dev/null +++ b/libacl/acl_check.c @@ -0,0 +1,130 @@ +/* + File: acl_check.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <acl/libacl.h> +#include "libacl.h" + + +#define FAIL_CHECK(error) \ + do { return error; } while (0) + +/* + Check if an ACL is valid. + + The e_id fields of ACL entries that don't use them are ignored. + + last + contains the index of the last valid entry found + after acl_check returns. + returns + 0 on success, -1 on error, or an ACL_*_ERROR value for invalid ACLs. +*/ + +int +acl_check( + acl_t acl, + int *last) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + id_t qual = 0; + int state = ACL_USER_OBJ; + acl_entry_obj *entry_obj_p; + int needs_mask = 0; + + if (!acl_obj_p) + return -1; + if (last) + *last = 0; + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + /* Check permissions for ~(ACL_READ|ACL_WRITE|ACL_EXECUTE) */ + switch (entry_obj_p->etag) { + case ACL_USER_OBJ: + if (state == ACL_USER_OBJ) { + qual = 0; + state = ACL_USER; + break; + } + FAIL_CHECK(ACL_MULTI_ERROR); + + case ACL_USER: + if (state != ACL_USER) + FAIL_CHECK(ACL_MISS_ERROR); + if (qualifier_obj_id(entry_obj_p->eid) < qual || + qualifier_obj_id(entry_obj_p->eid) == + ACL_UNDEFINED_ID) + FAIL_CHECK(ACL_DUPLICATE_ERROR); + qual = qualifier_obj_id(entry_obj_p->eid)+1; + needs_mask = 1; + break; + + case ACL_GROUP_OBJ: + if (state == ACL_USER) { + qual = 0; + state = ACL_GROUP; + break; + } + if (state >= ACL_GROUP) + FAIL_CHECK(ACL_MULTI_ERROR); + FAIL_CHECK(ACL_MISS_ERROR); + + case ACL_GROUP: + if (state != ACL_GROUP) + FAIL_CHECK(ACL_MISS_ERROR); + if (qualifier_obj_id(entry_obj_p->eid) < qual || + qualifier_obj_id(entry_obj_p->eid) == + ACL_UNDEFINED_ID) + FAIL_CHECK(ACL_DUPLICATE_ERROR); + qual = qualifier_obj_id(entry_obj_p->eid)+1; + needs_mask = 1; + break; + + case ACL_MASK: + if (state == ACL_GROUP) { + state = ACL_OTHER; + break; + } + if (state >= ACL_OTHER) + FAIL_CHECK(ACL_MULTI_ERROR); + FAIL_CHECK(ACL_MISS_ERROR); + + case ACL_OTHER: + if (state == ACL_OTHER || + (state == ACL_GROUP && !needs_mask)) { + state = 0; + break; + } + FAIL_CHECK(ACL_MISS_ERROR); + + default: + FAIL_CHECK(ACL_ENTRY_ERROR); + } + if (last) + (*last)++; + } + + if (state != 0) + FAIL_CHECK(ACL_MISS_ERROR); + return 0; +} +#undef FAIL_CHECK + diff --git a/libacl/acl_clear_perms.c b/libacl/acl_clear_perms.c new file mode 100644 index 0000000..e54e975 --- /dev/null +++ b/libacl/acl_clear_perms.c @@ -0,0 +1,36 @@ +/* + File: acl_clear_perms.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.3 */ +int +acl_clear_perms( + acl_permset_t permset_d) +{ + acl_permset_obj *acl_permset_obj_p = ext2int(acl_permset, permset_d); + if (!acl_permset_obj_p) + return -1; + acl_permset_obj_p->sperm = ACL_PERM_NONE; + return 0; +} + diff --git a/libacl/acl_cmp.c b/libacl/acl_cmp.c new file mode 100644 index 0000000..8a75149 --- /dev/null +++ b/libacl/acl_cmp.c @@ -0,0 +1,55 @@ +/* + File: acl_cmp.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +int +acl_cmp( + acl_t acl1, + acl_t acl2) +{ + acl_obj *acl1_obj_p = ext2int(acl, acl1), + *acl2_obj_p = ext2int(acl, acl2); + acl_entry_obj *p1_obj_p, *p2_obj_p; + if (!acl1_obj_p || !acl2_obj_p) + return -1; + if (acl1_obj_p->aused != acl2_obj_p->aused) + return 1; + p2_obj_p = acl2_obj_p->anext; + FOREACH_ACL_ENTRY(p1_obj_p, acl1_obj_p) { + if (p1_obj_p->etag != p2_obj_p->etag) + return 1; + if (!permset_obj_equal(p1_obj_p->eperm,p2_obj_p->eperm)) + return 1; + switch(p1_obj_p->etag) { + case ACL_USER: + case ACL_GROUP: + if (qualifier_obj_id(p1_obj_p->eid) != + qualifier_obj_id(p2_obj_p->eid)) + return 1; + + } + p2_obj_p = p2_obj_p->enext; + } + return 0; +} + diff --git a/libacl/acl_copy_entry.c b/libacl/acl_copy_entry.c new file mode 100644 index 0000000..c62e093 --- /dev/null +++ b/libacl/acl_copy_entry.c @@ -0,0 +1,42 @@ +/* + File: acl_copy_entry.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.4 */ +int +acl_copy_entry( + acl_entry_t dest_d, + acl_entry_t src_d) +{ + acl_entry_obj *dest_p = ext2int(acl_entry, dest_d), + *src_p = ext2int(acl_entry, src_d); + if (!dest_d || !src_p) + return -1; + + dest_p->etag = src_p->etag; + dest_p->eid = src_p->eid; + dest_p->eperm = src_p->eperm; + __acl_reorder_obj_p(dest_p); + return 0; +} + diff --git a/libacl/acl_copy_ext.c b/libacl/acl_copy_ext.c new file mode 100644 index 0000000..256ecf1 --- /dev/null +++ b/libacl/acl_copy_ext.c @@ -0,0 +1,55 @@ +/* + File: acl_copy_ext.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.5 */ +ssize_t +acl_copy_ext( + void *buf_p, + acl_t acl, + ssize_t size) +{ + struct __acl *acl_ext = (struct __acl *)buf_p; + struct __acl_entry *ent_p = acl_ext->x_entries; + acl_obj *acl_obj_p = ext2int(acl, acl); + acl_entry_obj *entry_obj_p; + ssize_t size_required; + + if (!acl_obj_p) + return -1; + size_required = sizeof(struct __acl) + + acl_obj_p->aused * sizeof(struct __acl_entry); + if (size < size_required) { + errno = ERANGE; + return -1; + } + acl_ext->x_size = size_required; + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + //ent_p->e_tag = cpu_to_le16(entry_obj_p->etag); + //ent_p->e_perm = cpu_to_le16(entry_obj_p->eperm.sperm); + //ent_p->e_id = cpu_to_le32(entry_obj_p->eid.quid); + *ent_p++ = entry_obj_p->eentry; + } + return 0; +} + diff --git a/libacl/acl_copy_int.c b/libacl/acl_copy_int.c new file mode 100644 index 0000000..04c26de --- /dev/null +++ b/libacl/acl_copy_int.c @@ -0,0 +1,65 @@ +/* + File: acl_copy_int.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.6 */ +acl_t +acl_copy_int( + const void *buf_p) +{ + const struct __acl *ext_acl = (struct __acl *)buf_p; + const struct __acl_entry *ent_p = ext_acl->x_entries, *end_p; + size_t size = ext_acl ? ext_acl->x_size : 0; + int entries; + acl_obj *acl_obj_p; + acl_entry_obj *entry_obj_p; + + if (!ext_acl || size < sizeof(struct __acl)) { + errno = EINVAL; + return NULL; + } + size -= sizeof(struct __acl); + if (size % sizeof(struct __acl_entry)) { + errno = EINVAL; + return NULL; + } + entries = size / sizeof(struct __acl_entry); + acl_obj_p = __acl_init_obj(); + if (acl_obj_p == NULL) + goto fail; + end_p = ext_acl->x_entries + entries; + for(; ent_p != end_p; ent_p++) { + entry_obj_p = __acl_create_entry_obj(acl_obj_p); + if (!entry_obj_p) + goto fail; + /* XXX Convert to machine endianness */ + entry_obj_p->eentry = *ent_p; + __acl_reorder_obj_p(entry_obj_p); + } + return int2ext(acl_obj_p); + +fail: + __acl_free_acl_obj(acl_obj_p); + return NULL; +} + diff --git a/libacl/acl_create_entry.c b/libacl/acl_create_entry.c new file mode 100644 index 0000000..5c5f036 --- /dev/null +++ b/libacl/acl_create_entry.c @@ -0,0 +1,69 @@ +/* + File: acl_create_entry.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +acl_entry_obj * +__acl_create_entry_obj( + acl_obj *acl_obj_p) +{ + acl_entry_obj *entry_obj_p; + + entry_obj_p = new_obj_p(acl_entry); + if (!entry_obj_p) + return NULL; + acl_obj_p->aused++; + + /* Insert at the end of the entry ring */ + entry_obj_p->eprev = acl_obj_p->aprev; + entry_obj_p->enext = (acl_entry_obj *)acl_obj_p; + entry_obj_p->eprev->enext = entry_obj_p; + entry_obj_p->enext->eprev = entry_obj_p; + + entry_obj_p->econtainer = acl_obj_p; + init_acl_entry_obj(*entry_obj_p); + + return entry_obj_p; +} + +/* 23.4.7 */ +int +acl_create_entry( + acl_t *acl_p, + acl_entry_t *entry_p) +{ + acl_obj *acl_obj_p; + acl_entry_obj *entry_obj_p; + if (!acl_p || !entry_p) { + errno = EINVAL; + return -1; + } + acl_obj_p = ext2int(acl, *acl_p); + if (!acl_obj_p) + return -1; + entry_obj_p = __acl_create_entry_obj(acl_obj_p); + if (entry_obj_p == NULL) + return -1; + *entry_p = int2ext(entry_obj_p); + return 0; +} + diff --git a/libacl/acl_delete_def_file.c b/libacl/acl_delete_def_file.c new file mode 100644 index 0000000..b64c877 --- /dev/null +++ b/libacl/acl_delete_def_file.c @@ -0,0 +1,40 @@ +/* + File: acl_delete_def_file.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <attr/xattr.h> +#include "byteorder.h" +#include "acl_ea.h" + + +/* 23.4.8 */ +int +acl_delete_def_file( + const char *path_p) +{ + int error; + + error = setxattr(path_p, ACL_EA_DEFAULT, NULL, 0, 0); + if (error < 0) + return -1; + return 0; +} + diff --git a/libacl/acl_delete_entry.c b/libacl/acl_delete_entry.c new file mode 100644 index 0000000..21b1c4a --- /dev/null +++ b/libacl/acl_delete_entry.c @@ -0,0 +1,46 @@ +/* + File: acl_delete_entry.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.9 */ +int +acl_delete_entry( + acl_t acl, + acl_entry_t entry_d) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + if (!acl_obj_p || !entry_obj_p) + return -1; + + + if (acl_obj_p->acurr == entry_obj_p) + acl_obj_p->acurr = acl_obj_p->acurr->eprev; + entry_obj_p->eprev->enext = entry_obj_p->enext; + entry_obj_p->enext->eprev = entry_obj_p->eprev; + + free_obj_p(entry_obj_p); + acl_obj_p->aused--; + return 0; +} + diff --git a/libacl/acl_delete_perm.c b/libacl/acl_delete_perm.c new file mode 100644 index 0000000..8a9bc5d --- /dev/null +++ b/libacl/acl_delete_perm.c @@ -0,0 +1,37 @@ +/* + File: acl_delete_perm.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.10 */ +int +acl_delete_perm( + acl_permset_t permset_d, + acl_perm_t perm) +{ + acl_permset_obj *acl_permset_obj_p = ext2int(acl_permset, permset_d); + if (!acl_permset_obj_p || (perm & !(ACL_READ|ACL_WRITE|ACL_EXECUTE))) + return -1; + acl_permset_obj_p->sperm &= ~perm; + return 0; +} + diff --git a/libacl/acl_dup.c b/libacl/acl_dup.c new file mode 100644 index 0000000..ffe55d0 --- /dev/null +++ b/libacl/acl_dup.c @@ -0,0 +1,55 @@ +/* + File: acl_dup.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.11 */ +acl_t +acl_dup( + acl_t acl) +{ + acl_entry_obj *entry_obj_p, *dup_entry_obj_p; + acl_obj *acl_obj_p = ext2int(acl, acl); + acl_obj *dup_obj_p; + + if (!acl_obj_p) + return NULL; + dup_obj_p = __acl_init_obj(); + if (!dup_obj_p) + return NULL; + + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + dup_entry_obj_p = __acl_create_entry_obj(dup_obj_p); + if (dup_entry_obj_p == NULL) + goto fail; + + dup_entry_obj_p->etag = entry_obj_p->etag; + dup_entry_obj_p->eid = entry_obj_p->eid; + dup_entry_obj_p->eperm = entry_obj_p->eperm; + } + return int2ext(dup_obj_p); + +fail: + __acl_free_acl_obj(dup_obj_p); + return NULL; +} + diff --git a/libacl/acl_entries.c b/libacl/acl_entries.c new file mode 100644 index 0000000..6c68afe --- /dev/null +++ b/libacl/acl_entries.c @@ -0,0 +1,34 @@ +/* + File: acl_entries.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +int +acl_entries( + acl_t acl) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + if (!acl_obj_p) + return -1; + return acl_obj_p->aused; +} + diff --git a/libacl/acl_entry_to_any_str.c b/libacl/acl_entry_to_any_str.c new file mode 100644 index 0000000..ed295d8 --- /dev/null +++ b/libacl/acl_entry_to_any_str.c @@ -0,0 +1,318 @@ +/* + File: acl_entry_to_any_str.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include <sys/stat.h> +#include <acl/libacl.h> +#include "libacl.h" + + +static ssize_t +snprint_uint( + char *text_p, + ssize_t size, + unsigned int i); +static const char * +user_name( + uid_t uid); +static const char * +group_name( + gid_t uid); + + +/* + Convert an ACL entry to text form. + + text_p + points to a buffer + size + the size of text_p + Returns + the size of the buffer that was used, or that + would be used (if size is too small). +*/ + +#define EFFECTIVE_STR "#effective:" + +#define ADVANCE(x) \ + text_p += (x); \ + size -= (x); \ + if (size < 0) \ + size = 0; + +#define ABBREV(s, str_len) \ + if (options & TEXT_ABBREVIATE) { \ + if (size > 0) \ + text_p[0] = *(s); \ + if (size > 1) \ + text_p[1] = ':'; \ + ADVANCE(2); \ + } else { \ + strncpy(text_p, (s), size); \ + ADVANCE(str_len); \ + } + +ssize_t +acl_entry_to_any_str( + const acl_entry_t entry_d, + char *text_p, + ssize_t size, + const acl_entry_t mask_d, + const char *prefix, + int options) +{ + #define TABS 4 + static const char *tabs = "\t\t\t\t"; + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + acl_entry_obj *mask_obj_p = NULL; + permset_t effective; + acl_tag_t type; + ssize_t x; + const char *orig_text_p = text_p, *str; + if (!entry_obj_p) + return -1; + if (mask_d) { + mask_obj_p = ext2int(acl_entry, mask_d); + if (!mask_obj_p) + return -1; + } + if (text_p == NULL) + size = 0; + + if (prefix) { + strncpy(text_p, prefix, size); + ADVANCE(strlen(prefix)); + } + + type = entry_obj_p->etag; + switch (type) { + case ACL_USER_OBJ: /* owner */ + mask_obj_p = NULL; + /* fall through */ + case ACL_USER: /* additional user */ + //strncpy(text_p, "user:", size); + //ADVANCE(5); + ABBREV("user:", 5); + if (type == ACL_USER) { + if (options & TEXT_NUMERIC_IDS) + str = NULL; + else + str = user_name(entry_obj_p->eid.qid); + if (str != NULL) { + strncpy(text_p, str, size); + ADVANCE(strlen(str)); + } else { + x = snprint_uint(text_p, size, + entry_obj_p->eid.qid); + ADVANCE(x); + } + } + if (size > 0) + *text_p = ':'; + ADVANCE(1); + break; + + case ACL_GROUP_OBJ: /* owning group */ + case ACL_GROUP: /* additional group */ + //strncpy(text_p, "group:", size); + //ADVANCE(6); + ABBREV("group:", 6); + if (type == ACL_GROUP) { + if (options & TEXT_NUMERIC_IDS) + str = NULL; + else + str = group_name(entry_obj_p->eid.qid); + if (str != NULL) { + strncpy(text_p, str, size); + ADVANCE(strlen(str)); + } else { + x = snprint_uint(text_p, size, + entry_obj_p->eid.qid); + ADVANCE(x); + } + } + if (size > 0) + *text_p = ':'; + ADVANCE(1); + break; + + + case ACL_MASK: /* acl mask */ + //strncpy(text_p, "mask:", size); + //ADVANCE(5); + ABBREV("mask:", 5); + if (size > 0) + *text_p = ':'; + ADVANCE(1); + break; + + case ACL_OTHER: /* other users */ + mask_obj_p = NULL; + /* fall through */ + //strncpy(text_p, "other:", size); + //ADVANCE(6); + ABBREV("other:", 6); + if (size > 0) + *text_p = ':'; + ADVANCE(1); + break; + + default: + return 0; + } + + switch ((size >= 3) ? 3 : size) { + case 3: + text_p[2] = (entry_obj_p->eperm.sperm & + ACL_EXECUTE) ? 'x' : '-'; + /* fall through */ + case 2: + text_p[1] = (entry_obj_p->eperm.sperm & + ACL_WRITE) ? 'w' : '-'; + /* fall through */ + case 1: + text_p[0] = (entry_obj_p->eperm.sperm & + ACL_READ) ? 'r' : '-'; + break; + } + ADVANCE(3); + + if (mask_obj_p && + (options & (TEXT_SOME_EFFECTIVE|TEXT_ALL_EFFECTIVE))) { + mask_obj_p = ext2int(acl_entry, mask_d); + if (!mask_obj_p) + return -1; + + effective = entry_obj_p->eperm.sperm & + mask_obj_p->eperm.sperm; + if (options & TEXT_NO_EFFECTIVE) + effective = ~ACL_PERM_NONE; + else if (options & TEXT_ALL_EFFECTIVE) + effective = ACL_PERM_NONE; + + if (effective != entry_obj_p->eperm.sperm) { + x = (options & TEXT_SMART_INDENT) ? + ((text_p - orig_text_p)/8) : TABS-1; + strncpy(text_p, tabs+x, size); + ADVANCE(TABS-x); + + strncpy(text_p, EFFECTIVE_STR, size); + ADVANCE(sizeof(EFFECTIVE_STR)-1); + + switch ((size >= 3) ? 3 : size) { + case 3: + text_p[2] = (effective & + ACL_EXECUTE) ? 'x' : '-'; + /* fall through */ + case 2: + text_p[1] = (effective & + ACL_WRITE) ? 'w' : '-'; + /* fall through */ + case 1: + text_p[0] = (effective & + ACL_READ) ? 'r' : '-'; + break; + } + ADVANCE(3); + + } + } + + /* zero-terminate string (but don't count '\0' character) */ + if (size > 0) + *text_p = '\0'; + + return (text_p - orig_text_p); /* total size required, excluding + final NULL character. */ +} + +#undef ADVANCE + + + +/* + This function is equivalent to the proposed changes to snprintf: + snprintf(text_p, size, "%u", i) + (The current snprintf returns -1 if the buffer is too small; the proposal + is to return the number of characters that would be required. See the + snprintf manual page.) +*/ + +static ssize_t +snprint_uint( + char *text_p, + ssize_t size, + unsigned int i) +{ + unsigned int tmp = i; + int digits = 1; + unsigned int factor = 1; + + while ((tmp /= 10) != 0) { + digits++; + factor *= 10; + } + if (size && (i == 0)) { + *text_p++ = '0'; + } else { + while (size > 0 && factor > 0) { + *text_p++ = '0' + (i / factor); + size--; + i %= factor; + factor /= 10; + } + } + if (size) + *text_p = '\0'; + + return digits; +} + + +static const char * +user_name( + uid_t uid) +{ + struct passwd *passwd = getpwuid(uid); + + if (passwd != NULL) + return passwd->pw_name; + else + return NULL; +} + + +static const char * +group_name( + gid_t gid) +{ + struct group *group = getgrgid(gid); + + if (group != NULL) + return group->gr_name; + else + return NULL; +} + diff --git a/libacl/acl_equiv_mode.c b/libacl/acl_equiv_mode.c new file mode 100644 index 0000000..59a36c6 --- /dev/null +++ b/libacl/acl_equiv_mode.c @@ -0,0 +1,68 @@ +/* + File: acl_equiv_mode.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <acl/libacl.h> +#include "libacl.h" + + +int +acl_equiv_mode( + acl_t acl, + mode_t *mode_p) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + acl_entry_obj *entry_obj_p; + int not_equiv = 0; + mode_t mode = 0; + if (!acl_obj_p) + return -1; + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + switch(entry_obj_p->etag) { + case ACL_USER_OBJ: + mode |= (entry_obj_p->eperm.sperm + & S_IRWXO) << 6; + break; + case ACL_GROUP_OBJ: + mode |= (entry_obj_p->eperm.sperm & + S_IRWXO) << 3; + break; + case ACL_OTHER: + mode |= (entry_obj_p->eperm.sperm & + S_IRWXO); + break; + case ACL_USER: + case ACL_GROUP: + case ACL_MASK: + not_equiv = 1; + break; + default: + errno = EINVAL; + return -1; + } + } + if (mode_p) + *mode_p = mode; + return not_equiv; +} + diff --git a/libacl/acl_error.c b/libacl/acl_error.c new file mode 100644 index 0000000..97a92ea --- /dev/null +++ b/libacl/acl_error.c @@ -0,0 +1,48 @@ +/* + File: acl_error.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <acl/libacl.h> +#include "libacl.h" + +#include <libintl.h> +#define _(String) gettext (String) + + +const char * +acl_error( + int code) +{ + switch(code) { + case ACL_MULTI_ERROR: + return _("Multiple entries"); + case ACL_DUPLICATE_ERROR: + return _("Duplicate entries"); + case ACL_MISS_ERROR: + return _("Missing or wrong entry"); + case ACL_ENTRY_ERROR: + return _("Invalid entry type"); + default: + return NULL; + } +} + diff --git a/libacl/acl_extended_fd.c b/libacl/acl_extended_fd.c new file mode 100644 index 0000000..d23d6ff --- /dev/null +++ b/libacl/acl_extended_fd.c @@ -0,0 +1,49 @@ +/* + File: acl_extended_fd.c + + Copyright (C) 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <attr/xattr.h> +#include "libacl.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +int +acl_extended_fd( + int fd) +{ + int base_size = sizeof(acl_ea_header) + 3 * sizeof(acl_ea_entry); + int retval; + + retval = fgetxattr(fd, ACL_EA_ACCESS, NULL, 0); + if (retval < 0 && errno != ENOATTR) + return -1; + if (retval > base_size) + return 1; + retval = fgetxattr(fd, ACL_EA_DEFAULT, NULL, 0); + if (retval < 0 && errno != ENOATTR) + return -1; + if (retval >= base_size) + return 1; + return 0; +} + diff --git a/libacl/acl_extended_file.c b/libacl/acl_extended_file.c new file mode 100644 index 0000000..12ac959 --- /dev/null +++ b/libacl/acl_extended_file.c @@ -0,0 +1,49 @@ +/* + File: acl_extended_file.c + + Copyright (C) 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <attr/xattr.h> +#include "libacl.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +int +acl_extended_file( + const char *path_p) +{ + int base_size = sizeof(acl_ea_header) + 3 * sizeof(acl_ea_entry); + int retval; + + retval = getxattr(path_p, ACL_EA_ACCESS, NULL, 0); + if (retval < 0 && errno != ENOATTR) + return -1; + if (retval > base_size) + return 1; + retval = getxattr(path_p, ACL_EA_DEFAULT, NULL, 0); + if (retval < 0 && errno != ENOATTR) + return -1; + if (retval >= base_size) + return 1; + return 0; +} + diff --git a/libacl/acl_free.c b/libacl/acl_free.c new file mode 100644 index 0000000..38c976e --- /dev/null +++ b/libacl/acl_free.c @@ -0,0 +1,76 @@ +/* + File: acl_free.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +void +__acl_free_acl_obj(acl_obj *acl_obj_p) +{ + acl_entry_obj *entry_obj_p; + while (acl_obj_p->anext != (acl_entry_obj *)acl_obj_p) { + entry_obj_p = acl_obj_p->anext; + acl_obj_p->anext = acl_obj_p->anext->enext; + free_obj_p(entry_obj_p); + } + free_obj_p(acl_obj_p); +} + + +/* 23.4.12 */ +int +acl_free( + void *obj_p) +{ + obj_prefix *int_p = ((obj_prefix *)obj_p)-1; + if (!obj_p || !int_p) { + errno = EINVAL; + return -1; + } + + + switch(int_p->p_magic) { + case acl_MAGIC: + __acl_free_acl_obj((acl_obj *)int_p); + return 0; + case qualifier_MAGIC: + case string_MAGIC: + free_obj_p(int_p); + return 0; + case acl_entry_MAGIC: + case acl_permset_MAGIC: +#ifdef LIBACL_DEBUG + fprintf(stderr, "object (magic=0x%X) " + "at %p cannot be freed\n", + int_p->p_magic, int_p); +#endif + break; + default: +#ifdef LIBACL_DEBUG + fprintf(stderr, "invalid object (magic=0x%X) " + "at %p\n", int_p->p_magic, int_p); +#endif + break; + } + errno = EINVAL; + return -1; +} + diff --git a/libacl/acl_from_mode.c b/libacl/acl_from_mode.c new file mode 100644 index 0000000..90a871e --- /dev/null +++ b/libacl/acl_from_mode.c @@ -0,0 +1,74 @@ +/* + File: acl_from_mode.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <acl/libacl.h> +#include "libacl.h" + + +/* + Create an ACL from a file mode. + + returns + the new ACL. +*/ + +acl_t +acl_from_mode( + mode_t mode) +{ + acl_obj *acl_obj_p; + acl_entry_obj *entry_obj_p; + + acl_obj_p = __acl_init_obj(); + if (!acl_obj_p) + goto fail; + + entry_obj_p = __acl_create_entry_obj(acl_obj_p); + if (!entry_obj_p) + goto fail; + entry_obj_p->etag = ACL_USER_OBJ; + entry_obj_p->eid.qid = ACL_UNDEFINED_ID; + entry_obj_p->eperm.sperm = (mode & S_IRWXU) >> 6; + + entry_obj_p = __acl_create_entry_obj(acl_obj_p); + if (!entry_obj_p) + goto fail; + entry_obj_p->etag = ACL_GROUP_OBJ; + entry_obj_p->eid.qid = ACL_UNDEFINED_ID; + entry_obj_p->eperm.sperm = (mode & S_IRWXG) >> 3; + + entry_obj_p = __acl_create_entry_obj(acl_obj_p); + if (!entry_obj_p) + goto fail; + entry_obj_p->etag = ACL_OTHER; + entry_obj_p->eid.qid = ACL_UNDEFINED_ID; + entry_obj_p->eperm.sperm = mode & S_IRWXO; + return int2ext(acl_obj_p); + +fail: + __acl_free_acl_obj(acl_obj_p); + return NULL; +} + diff --git a/libacl/acl_from_text.c b/libacl/acl_from_text.c new file mode 100644 index 0000000..2a01a57 --- /dev/null +++ b/libacl/acl_from_text.c @@ -0,0 +1,326 @@ +/* + File: acl_from_text.c + + Copyright (C) 1999, 2000, 2001 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include "libacl.h" + + +#define SKIP_WS(x) do { \ + while (*(x)==' ' || *(x)=='\t' || *(x)=='\n' || *(x)=='\r') \ + (x)++; \ + if (*(x)=='#') { \ + while (*(x)!='\n' && *(x)!='\0') \ + (x)++; \ + } \ + } while (0) + + +static int +parse_acl_entry( + const char **text_p, + acl_t *acl_p); + + +/* 23.4.13 */ +acl_t +acl_from_text( + const char *buf_p) +{ + acl_t acl; + acl = acl_init(0); + if (!acl) + return NULL; + if (!buf_p) { + errno = EINVAL; + return NULL; + } + while (*buf_p != '\0') { + if (parse_acl_entry(&buf_p, &acl) != 0) + goto fail; + SKIP_WS(buf_p); + if (*buf_p == ',') { + buf_p++; + SKIP_WS(buf_p); + } + } + if (*buf_p != '\0') { + errno = EINVAL; + goto fail; + } + + return acl; + +fail: + acl_free(acl); + return NULL; +} + + +static int +skip_tag_name( + const char **text_p, + const char *token) +{ + size_t len = strlen(token); + const char *text = *text_p; + + SKIP_WS(text); + if (strncmp(text, token, len) == 0) { + text += len; + goto delimiter; + } + if (*text == *token) { + text++; + goto delimiter; + } + return 0; + +delimiter: + SKIP_WS(text); + if (*text == ':') + text++; + *text_p = text; + return 1; +} + + +static char * +get_token( + const char **text_p) +{ + char *token = NULL; + const char *ep; + + ep = *text_p; + SKIP_WS(ep); + + while (*ep!='\0' && *ep!='\r' && *ep!='\n' && *ep!=':' && *ep!=',') + ep++; + if (ep == *text_p) + goto after_token; + token = (char*)malloc(ep - *text_p + 1); + if (token == 0) + goto after_token; + memcpy(token, *text_p, (ep - *text_p)); + token[ep - *text_p] = '\0'; +after_token: + if (*ep == ':') + ep++; + *text_p = ep; + return token; +} + + +static int +get_id( + const char *token, + id_t *id_p) +{ + char *ep; + long l; + l = strtol(token, &ep, 0); + if (*ep != '\0') + return -1; + if (l < 0) { + /* + Negative values are interpreted as 16-bit numbers, + so that id -2 maps to 65534 (nobody/nogroup), etc. + */ + l &= 0xFFFF; + } + *id_p = l; + return 0; +} + + +static int +get_uid( + const char *token, + uid_t *uid_p) +{ + struct passwd *passwd; + + if (get_id(token, uid_p) == 0) + goto accept; + passwd = getpwnam(token); + if (passwd) { + *uid_p = passwd->pw_uid; + goto accept; + } + return -1; + +accept: + return 0; +} + + +static int +get_gid( + const char *token, + gid_t *gid_p) +{ + struct group *group; + + if (get_id(token, (uid_t *)gid_p) == 0) + goto accept; + group = getgrnam(token); + if (group) { + *gid_p = group->gr_gid; + goto accept; + } + return -1; + +accept: + return 0; +} + + +/* + Parses the next acl entry in text_p. + + Returns: + -1 on error, 0 on success. +*/ + +static int +parse_acl_entry( + const char **text_p, + acl_t *acl_p) +{ + acl_entry_obj entry_obj; + acl_entry_t entry_d; + char *str; + const char *backup; + int error, perm_chars; + + init_obj(acl_entry, entry_obj); + init_acl_entry_obj(entry_obj); + + /* parse acl entry type */ + SKIP_WS(*text_p); + switch (**text_p) { + case 'u': /* user */ + if (!skip_tag_name(text_p, "user")) + goto bad_tag_name; + backup = *text_p; + str = get_token(text_p); + if (str) { + entry_obj.etag = ACL_USER; + error = get_uid(str, &entry_obj.eid.qid); + free(str); + if (error) { + *text_p = backup; + return -1; + } + } else { + entry_obj.etag = ACL_USER_OBJ; + } + break; + + case 'g': /* group */ + if (!skip_tag_name(text_p, "group")) + goto bad_tag_name; + backup = *text_p; + str = get_token(text_p); + if (str) { + entry_obj.etag = ACL_GROUP; + error = get_gid(str, &entry_obj.eid.qid); + free(str); + if (error) { + *text_p = backup; + return -1; + } + } else { + entry_obj.etag = ACL_GROUP_OBJ; + } + break; + + case 'm': /* mask */ + if (!skip_tag_name(text_p, "mask")) + goto bad_tag_name; + /* skip empty entry qualifier field (this field may + be missing for compatibility with Solaris.) */ + SKIP_WS(*text_p); + if (**text_p == ':') + (*text_p)++; + entry_obj.etag = ACL_MASK; + break; + + case 'o': /* other */ + if (!skip_tag_name(text_p, "other")) + goto bad_tag_name; + /* skip empty entry qualifier field (this field may + be missing for compatibility with Solaris.) */ + SKIP_WS(*text_p); + if (**text_p == ':') + (*text_p)++; + entry_obj.etag = ACL_OTHER; + break; + + default: + goto bad_tag_name; + } + + for (perm_chars=0; perm_chars<3; perm_chars++, (*text_p)++) { + switch(**text_p) { + case 'r': + if (entry_obj.eperm.sperm & ACL_READ) + return -1; + entry_obj.eperm.sperm |= ACL_READ; + break; + + case 'w': + if (entry_obj.eperm.sperm & ACL_WRITE) + return -1; + entry_obj.eperm.sperm |= ACL_WRITE; + break; + + case 'x': + if (entry_obj.eperm.sperm & ACL_EXECUTE) + return -1; + entry_obj.eperm.sperm |= ACL_EXECUTE; + break; + + case '-': + /* ignore */ + break; + + default: + if (perm_chars == 0) + return -1; + goto create_entry; + } + } + +create_entry: + if (acl_create_entry(acl_p, &entry_d) != 0) + return -1; + if (acl_copy_entry(entry_d, int2ext(&entry_obj)) != 0) + return -1; + return 0; + +bad_tag_name: + errno = EINVAL; + return -1; +} + diff --git a/libacl/acl_get_entry.c b/libacl/acl_get_entry.c new file mode 100644 index 0000000..72b0f90 --- /dev/null +++ b/libacl/acl_get_entry.c @@ -0,0 +1,59 @@ +/* + File: acl_get_entry.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.14 */ +int +acl_get_entry( + acl_t acl, + int entry_id, + acl_entry_t *entry_p) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + if (!acl_obj_p) + return -1; + if (!entry_p) { + errno = EINVAL; + return -1; + } + + if (entry_id == ACL_FIRST_ENTRY) { + acl_obj_p->acurr = acl_obj_p->anext; + } else if (entry_id == ACL_NEXT_ENTRY) { + /*if (acl_obj_p->acurr == (acl_entry_obj *)acl_obj_p) { + errno = EINVAL; + return -1; + }*/ + acl_obj_p->acurr = acl_obj_p->acurr->enext; + } + if (acl_obj_p->acurr == (acl_entry_obj *)acl_obj_p) { + *entry_p = NULL; + return 0; + } + if (!check_obj_p(acl_entry, acl_obj_p->acurr)) { + return -1; + } + *entry_p = int2ext(acl_obj_p->acurr); + return 1; +} + diff --git a/libacl/acl_get_fd.c b/libacl/acl_get_fd.c new file mode 100644 index 0000000..ff859a3 --- /dev/null +++ b/libacl/acl_get_fd.c @@ -0,0 +1,62 @@ +/* + File: acl_get_fd.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <stdio.h> +#include <attr/xattr.h> +#include <acl/libacl.h> +#include "libacl.h" +#include "__acl_from_xattr.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +/* 23.4.15 */ +acl_t +acl_get_fd( + int fd) +{ + const size_t size_guess = acl_ea_size(16); + char *ext_acl_p = alloca(size_guess); + int retval; + + if (!ext_acl_p) + return NULL; + retval = fgetxattr(fd, ACL_EA_ACCESS, ext_acl_p, size_guess); + if (retval == -1 && errno == ERANGE) { + retval = fgetxattr(fd, ACL_EA_ACCESS, NULL, 0); + if (retval > 0) { + ext_acl_p = alloca(retval); + if (!ext_acl_p) + return NULL; + retval = fgetxattr(fd, ACL_EA_ACCESS, ext_acl_p,retval); + } + } + if (retval > 0) { + acl_t acl = __acl_from_xattr(ext_acl_p, retval); + return acl; + } else if (retval == 0 || errno == ENOATTR) { + return acl_get_fd_mode(fd); + } else + return NULL; +} + diff --git a/libacl/acl_get_fd_mode.c b/libacl/acl_get_fd_mode.c new file mode 100644 index 0000000..8bc1a74 --- /dev/null +++ b/libacl/acl_get_fd_mode.c @@ -0,0 +1,43 @@ +/* + File: acl_get_fd_mode.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <acl/libacl.h> +#include "libacl.h" + + +/* +Same as acl_get_file, but based on the file mode permission bits. +*/ + +acl_t +acl_get_fd_mode( + int fd) +{ + struct stat st; + + if (fstat(fd, &st) != 0) + return NULL; + return acl_from_mode(st.st_mode); +} + diff --git a/libacl/acl_get_file.c b/libacl/acl_get_file.c new file mode 100644 index 0000000..b25b920 --- /dev/null +++ b/libacl/acl_get_file.c @@ -0,0 +1,79 @@ +/* + File: acl_get_file.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <stdio.h> +#include <attr/xattr.h> +#include <acl/libacl.h> +#include "libacl.h" +#include "__acl_from_xattr.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +/* 23.4.16 */ +acl_t +acl_get_file( + const char *path_p, + acl_type_t type) +{ + const size_t size_guess = acl_ea_size(16); + char *ext_acl_p = alloca(size_guess); + const char *name; + int retval; + + switch(type) { + case ACL_TYPE_ACCESS: + name = ACL_EA_ACCESS; + break; + case ACL_TYPE_DEFAULT: + name = ACL_EA_DEFAULT; + break; + default: + errno = EINVAL; + return NULL; + } + + if (!ext_acl_p) + return NULL; + retval = getxattr(path_p, name, ext_acl_p, size_guess); + if (retval == -1 && errno == ERANGE) { + retval = getxattr(path_p, ACL_EA_ACCESS, NULL, 0); + if (retval > 0) { + ext_acl_p = alloca(retval); + if (!ext_acl_p) + return NULL; + retval = getxattr(path_p, name, ext_acl_p, retval); + } + } + if (retval > 0) { + acl_t acl = __acl_from_xattr(ext_acl_p, retval); + return acl; + } else if (retval == 0 || errno == ENOATTR) { + if (type == ACL_TYPE_ACCESS) + return acl_get_file_mode(path_p); + else + return acl_init(0); + } else + return NULL; +} + diff --git a/libacl/acl_get_file_mode.c b/libacl/acl_get_file_mode.c new file mode 100644 index 0000000..bd11c40 --- /dev/null +++ b/libacl/acl_get_file_mode.c @@ -0,0 +1,43 @@ +/* + File: acl_get_file_mode.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <acl/libacl.h> +#include "libacl.h" + + +/* +Same as acl_get_file, but based on the file mode permission bits. +*/ + +acl_t +acl_get_file_mode( + const char *path_p) +{ + struct stat st; + + if (stat(path_p, &st) != 0) + return NULL; + return acl_from_mode(st.st_mode); +} + diff --git a/libacl/acl_get_perm.c b/libacl/acl_get_perm.c new file mode 100644 index 0000000..4fb0d14 --- /dev/null +++ b/libacl/acl_get_perm.c @@ -0,0 +1,35 @@ +/* + File: acl_get_perm.c + + Copyright (C) 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +int +acl_get_perm( + acl_permset_t permset_d, + acl_perm_t perm) +{ + acl_permset_obj *acl_permset_obj_p = ext2int(acl_permset, permset_d); + if (!acl_permset_obj_p || (perm & !(ACL_READ|ACL_WRITE|ACL_EXECUTE))) + return -1; + return (acl_permset_obj_p->sperm & perm) != 0; +} + diff --git a/libacl/acl_get_permset.c b/libacl/acl_get_permset.c new file mode 100644 index 0000000..1521697 --- /dev/null +++ b/libacl/acl_get_permset.c @@ -0,0 +1,41 @@ +/* + File: acl_get_permset.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.17 */ +int +acl_get_permset( + acl_entry_t entry_d, + acl_permset_t *permset_p) +{ + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + if (!entry_obj_p) + return -1; + if (!permset_p) { + errno = EINVAL; + return -1; + } + *permset_p = int2ext(&entry_obj_p->eperm); + return 0; +} + diff --git a/libacl/acl_get_qualifier.c b/libacl/acl_get_qualifier.c new file mode 100644 index 0000000..843f71e --- /dev/null +++ b/libacl/acl_get_qualifier.c @@ -0,0 +1,49 @@ +/* + File: acl_get_qualifier.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.18 */ +void * +acl_get_qualifier( + acl_entry_t entry_d) +{ + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + qualifier_obj *qualifier_obj_p; + if (!entry_obj_p) + return NULL; + + switch(entry_obj_p->etag) { + case ACL_USER: + case ACL_GROUP: + break; + default: + errno = EINVAL; + return NULL; + } + qualifier_obj_p = new_obj_p(qualifier); + if (!qualifier_obj_p) + return NULL; + qualifier_obj_p->qid = entry_obj_p->eid.qid; + return int2ext(qualifier_obj_p); +} + diff --git a/libacl/acl_get_tag_type.c b/libacl/acl_get_tag_type.c new file mode 100644 index 0000000..2fd2683 --- /dev/null +++ b/libacl/acl_get_tag_type.c @@ -0,0 +1,41 @@ +/* + File: acl_get_tag_type.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.19 */ +int +acl_get_tag_type( + acl_entry_t entry_d, + acl_tag_t *tag_type_p) +{ + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + if (!entry_obj_p) + return -1; + if (!tag_type_p) { + errno = EINVAL; + return -1; + } + *tag_type_p = entry_obj_p->etag; + return 0; +} + diff --git a/libacl/acl_init.c b/libacl/acl_init.c new file mode 100644 index 0000000..6b112b0 --- /dev/null +++ b/libacl/acl_init.c @@ -0,0 +1,50 @@ +/* + File: acl_init.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +acl_obj * +__acl_init_obj( + void) +{ + acl_obj *acl_obj_p = new_obj_p(acl); + if (!acl_obj_p) + return NULL; + acl_obj_p->aused = 0; + acl_obj_p->aprev = acl_obj_p->anext = (acl_entry_obj *)acl_obj_p; + acl_obj_p->acurr = (acl_entry_obj *)acl_obj_p; + return acl_obj_p; +} + + +/* 23.4.20 */ +acl_t +acl_init( + int count) +{ + if (count < 0) { + errno = EINVAL; + return NULL; + } + return int2ext(__acl_init_obj()); +} + diff --git a/libacl/acl_print.c b/libacl/acl_print.c new file mode 100644 index 0000000..45831c3 --- /dev/null +++ b/libacl/acl_print.c @@ -0,0 +1,90 @@ +/* + File: acl_print.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <acl/libacl.h> +#include "libacl.h" + + +/* + Print an ACL to a stream. + + returns + the number of characters written, or -1 on error. +*/ + +int +acl_print( + FILE *file, + acl_t acl, + const char *prefix, + int options) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + acl_entry_obj *entry_obj_p, *mask_obj_p = NULL; + int n, written = 0, len, size = 256; + char *text_p, *tmp; + if (!acl_obj_p) + return -1; + text_p = (char*)malloc(size); + if (text_p == NULL) + return -1; + + if (options & (TEXT_SOME_EFFECTIVE|TEXT_ALL_EFFECTIVE)) { + /* fetch the ACL_MASK entry */ + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + if (entry_obj_p->etag == ACL_MASK) { + mask_obj_p = entry_obj_p; + break; + } + } + } + + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + len = acl_entry_to_any_str(int2ext(entry_obj_p), text_p, size, + int2ext(mask_obj_p), prefix, options); + if (len < 0) + goto fail; + if (size < len) { + while (size < len) + size <<= 1; + tmp = (char*)realloc(text_p, size); + if (!tmp) + goto fail; + text_p = tmp; + continue; + } + + n = fprintf(file, "%s\n", text_p); + if (n < 0) + goto fail; + written += n; + } + + free(text_p); + return written; + +fail: + free(text_p); + return -1; +} + diff --git a/libacl/acl_set_fd.c b/libacl/acl_set_fd.c new file mode 100644 index 0000000..a8a711b --- /dev/null +++ b/libacl/acl_set_fd.c @@ -0,0 +1,52 @@ +/* + File: acl_set_fd.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <attr/xattr.h> +#include "libacl.h" +#include "__acl_to_xattr.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +/* 23.4.21 */ +int +acl_set_fd( + int fd, + acl_t acl) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + char *ext_acl_p; + const char *name = ACL_EA_ACCESS; + size_t size; + int error; + + if (!acl_obj_p) + return -1; + ext_acl_p = __acl_to_xattr(acl_obj_p, &size); + if (!ext_acl_p) + return -1; + error = fsetxattr(fd, name, (char *)ext_acl_p, size, 0); + free(ext_acl_p); + return error; +} + diff --git a/libacl/acl_set_fd_mode.c b/libacl/acl_set_fd_mode.c new file mode 100644 index 0000000..541c5be --- /dev/null +++ b/libacl/acl_set_fd_mode.c @@ -0,0 +1,53 @@ +/* + File: acl_set_fd_mode.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <acl/libacl.h> +#include "libacl.h" + + +/* +Same as acl_set_fd, but uses file mode permission bits. +*/ + +int +acl_set_fd_mode( + int fd, + acl_t acl) +{ + struct stat st; + mode_t mode; + int error; + + error = acl_equiv_mode(acl, &mode); + if (error != 0) { + if (error > 0) + errno = ENOTSUP; + return -1; + } + if (fstat(fd, &st) != 0) + return -1; + mode |= st.st_mode & ~(S_IRWXU|S_IRWXG|S_IRWXO); + return fchmod(fd, mode); +} + diff --git a/libacl/acl_set_file.c b/libacl/acl_set_file.c new file mode 100644 index 0000000..24c27c5 --- /dev/null +++ b/libacl/acl_set_file.c @@ -0,0 +1,64 @@ +/* + File: acl_set_file.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <unistd.h> +#include <attr/xattr.h> +#include "libacl.h" +#include "__acl_to_xattr.h" + +#include "byteorder.h" +#include "acl_ea.h" + + +/* 23.4.22 */ +int +acl_set_file( + const char *path_p, + acl_type_t type, + acl_t acl) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + char *ext_acl_p; + const char *name; + size_t size; + int error; + + if (!acl_obj_p) + return -1; + switch (type) { + case ACL_TYPE_ACCESS: + name = ACL_EA_ACCESS; + break; + case ACL_TYPE_DEFAULT: + name = ACL_EA_DEFAULT; + break; + default: + errno = EINVAL; + return -1; + } + ext_acl_p = __acl_to_xattr(acl_obj_p, &size); + if (!ext_acl_p) + return -1; + error = setxattr(path_p, name, (char *)ext_acl_p, size, 0); + free(ext_acl_p); + return error; +} + diff --git a/libacl/acl_set_file_mode.c b/libacl/acl_set_file_mode.c new file mode 100644 index 0000000..b233f29 --- /dev/null +++ b/libacl/acl_set_file_mode.c @@ -0,0 +1,67 @@ +/* + File: acl_set_file_mode.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <acl/libacl.h> +#include "libacl.h" + + +/* +Same as acl_set_file, but based on the file mode permission bits. +*/ + +int +acl_set_file_mode( + const char *path_p, + acl_type_t type, + acl_t acl) +{ + struct stat st; + mode_t mode; + int error; + + switch(type) { + case ACL_TYPE_ACCESS: + error = acl_equiv_mode(acl, &mode); + if (error != 0) { + if (error > 0) + errno = ENOTSUP; + return -1; + } + if (stat(path_p, &st) != 0) + return -1; + mode |= st.st_mode & ~(S_IRWXU|S_IRWXG|S_IRWXO); + return chmod(path_p, mode); + + case ACL_TYPE_DEFAULT: + if (acl_entries(acl) == 0) + return 0; + errno = ENOTSUP; + return -1; + + default: + errno = EINVAL; + return -1; + } +} + diff --git a/libacl/acl_set_permset.c b/libacl/acl_set_permset.c new file mode 100644 index 0000000..146d782 --- /dev/null +++ b/libacl/acl_set_permset.c @@ -0,0 +1,38 @@ +/* + File: acl_set_permset.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.23 */ +int +acl_set_permset( + acl_entry_t entry_d, + acl_permset_t permset_d) +{ + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + acl_permset_obj *acl_permset_obj_p = ext2int(acl_permset, permset_d); + if (!entry_obj_p || !acl_permset_obj_p) + return -1; + entry_obj_p->eperm.i = acl_permset_obj_p->i; + return 0; +} + diff --git a/libacl/acl_set_qualifier.c b/libacl/acl_set_qualifier.c new file mode 100644 index 0000000..bc46a02 --- /dev/null +++ b/libacl/acl_set_qualifier.c @@ -0,0 +1,50 @@ +/* + File: acl_set_qualifier.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.24 */ +int +acl_set_qualifier( + acl_entry_t entry_d, + const void *tag_qualifier_p) +{ + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + if (!entry_obj_p) + return -1; + + + switch(entry_obj_p->etag) { + case ACL_USER: + entry_obj_p->eid.qid = *(id_t *)tag_qualifier_p; + break; + case ACL_GROUP: + entry_obj_p->eid.qid = *(id_t *)tag_qualifier_p; + break; + default: + errno = EINVAL; + return -1; + } + __acl_reorder_obj_p(entry_obj_p); + return 0; +} + diff --git a/libacl/acl_set_tag_type.c b/libacl/acl_set_tag_type.c new file mode 100644 index 0000000..05464e8 --- /dev/null +++ b/libacl/acl_set_tag_type.c @@ -0,0 +1,49 @@ +/* + File: acl_set_tag_type.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.25 */ +int +acl_set_tag_type( + acl_entry_t entry_d, + acl_tag_t tag_type) +{ + acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d); + if (!entry_obj_p) + return -1; + switch(tag_type) { + case ACL_USER_OBJ: + case ACL_USER: + case ACL_GROUP_OBJ: + case ACL_GROUP: + case ACL_MASK: + case ACL_OTHER: + entry_obj_p->etag = tag_type; + __acl_reorder_obj_p(entry_obj_p); + return 0; + default: + errno = EINVAL; + return -1; + } +} + diff --git a/libacl/acl_size.c b/libacl/acl_size.c new file mode 100644 index 0000000..d2b688d --- /dev/null +++ b/libacl/acl_size.c @@ -0,0 +1,36 @@ +/* + File: acl_size.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "libacl.h" + + +/* 23.4.26 */ +ssize_t +acl_size( + acl_t acl) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + if (!acl_obj_p) + return -1; + return sizeof(struct __acl) + + acl_obj_p->aused * sizeof(struct __acl_entry); +} + diff --git a/libacl/acl_to_any_text.c b/libacl/acl_to_any_text.c new file mode 100644 index 0000000..c4608f9 --- /dev/null +++ b/libacl/acl_to_any_text.c @@ -0,0 +1,98 @@ +/* + File: acl_to_any_text.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <acl/libacl.h> +#include "libacl.h" + +char * +acl_to_any_text( + acl_t acl, + ssize_t *len_p, + const char *prefix, + char separator, + const char *suffix, + int options) +{ + acl_obj *acl_obj_p = ext2int(acl, acl); + ssize_t size, len = 0, entry_len = 0, + suffix_len = suffix ? strlen(suffix) : 0; + string_obj *string_obj_p, *tmp; + acl_entry_obj *entry_obj_p, *mask_obj_p = NULL; + if (!acl_obj_p) + return NULL; + size = acl->a_used * 15 + 1; + string_obj_p = new_var_obj_p(string, size); + if (!string_obj_p) + return NULL; + + if (options & (TEXT_SOME_EFFECTIVE|TEXT_ALL_EFFECTIVE)) { + /* fetch the ACL_MASK entry */ + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + if (entry_obj_p->etag == ACL_MASK) { + mask_obj_p = entry_obj_p; + break; + } + } + } + + FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) { + if (len + entry_len + 1 > size) { + while (len + entry_len + 1 > size) + size <<= 1; + tmp = realloc_var_obj_p(string, string_obj_p, size); + if (tmp == NULL) + goto fail; + string_obj_p = tmp; + } + + entry_len = acl_entry_to_any_str(int2ext(entry_obj_p), + string_obj_p->sstr + len, + size-len, + int2ext(mask_obj_p), + prefix, + options); + if (entry_len < 0) + goto fail; + if (len + entry_len + suffix_len + 1 > size) + continue; + len += entry_len; + string_obj_p->sstr[len] = separator; + len++; + } + if (len) + len--; + if (len && suffix) { + strcpy(string_obj_p->sstr + len, suffix); + len += suffix_len; + } else + string_obj_p->sstr[len] = '\0'; + + if (len_p) + *len_p = len; + return (char *)int2ext(string_obj_p); + +fail: + free_obj_p(string_obj_p); + return NULL; +} + diff --git a/libacl/acl_to_text.c b/libacl/acl_to_text.c new file mode 100644 index 0000000..8782baa --- /dev/null +++ b/libacl/acl_to_text.c @@ -0,0 +1,34 @@ +/* + File: acl_to_text.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <acl/libacl.h> +#include "libacl.h" + +char * +acl_to_text( + acl_t acl, + ssize_t *len_p) +{ + return acl_to_any_text(acl, len_p, "", '\n', "\n", TEXT_NO_EFFECTIVE); +} + diff --git a/libacl/acl_valid.c b/libacl/acl_valid.c new file mode 100644 index 0000000..d7c0d76 --- /dev/null +++ b/libacl/acl_valid.c @@ -0,0 +1,42 @@ +/* + File: acl_valid.c + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <errno.h> +#include <sys/acl.h> +#include "libacl.h" + + +/* 23.4.28 */ +int +acl_valid( + acl_t acl) +{ + int result; + + result = acl_check(acl, NULL); + if (result != 0) { + if (result > 0) + errno = EINVAL; + return -1; + } + return 0; +} + diff --git a/libacl/byteorder.h b/libacl/byteorder.h new file mode 100644 index 0000000..4cd35c0 --- /dev/null +++ b/libacl/byteorder.h @@ -0,0 +1,38 @@ +#include "config.h" + +#ifndef __u16 +# if SIZEOF_SHORT == 2 +# define __u16 unsigned short +# elif SIZEOF_INT == 2 +# define __u16 unsigned int +# else +# error Neither short nor int are 16-bit values. +# endif +#endif + +#ifndef __u32 +# if SIZEOF_INT == 4 +# define __u32 unsigned int +# elif SIZEOF_LONG == 4 +# define __u32 unsigned long +# else +# error Neither int nor long are 32-bit values. +# endif +#endif + +#ifdef WORDS_BIGENDIAN +# define cpu_to_le16(w16) le16_to_cpu(w16) +# define le16_to_cpu(w16) ((__u16)((__u16)(w16) >> 8) | \ + (__u16)((__u16)(w16) << 8)) +# define cpu_to_le32(w32) le32_to_cpu(w32) +# define le32_to_cpu(w32) ((__u32)( (__u32)(w32) >>24) | \ + (__u32)(((__u32)(w32) >> 8) & 0xFF00) | \ + (__u32)(((__u32)(w32) << 8) & 0xFF0000) | \ + (__u32)( (__u32)(w32) <<24)) +#else +# define cpu_to_le16(w16) ((__u16)(w16)) +# define le16_to_cpu(w16) ((__u16)(w16)) +# define cpu_to_le32(w32) ((__u32)(w32)) +# define le32_to_cpu(w32) ((__u32)(w32)) +#endif + diff --git a/libacl/libacl.h b/libacl/libacl.h new file mode 100644 index 0000000..b25f5dd --- /dev/null +++ b/libacl/libacl.h @@ -0,0 +1,114 @@ +#include <errno.h> +#include <sys/acl.h> +#include "libobj.h" + +typedef unsigned int permset_t; + +#define ACL_PERM_NONE (0x0000) + +/* object types */ +struct acl_permset_obj_tag; +typedef struct acl_permset_obj_tag acl_permset_obj; +struct qualifier_obj_tag; +typedef struct qualifier_obj_tag qualifier_obj; +struct acl_entry_obj_tag; +typedef struct acl_entry_obj_tag acl_entry_obj; +struct acl_obj_tag; +typedef struct acl_obj_tag acl_obj; + +/* permset_t object */ +struct __acl_permset_ext { + permset_t s_perm; +}; +struct acl_permset_obj_tag { + obj_prefix o_prefix; + struct __acl_permset_ext i; +}; + +#define sperm i.s_perm +#define oprefix i.o_prefix + +#define permset_obj_equal(s1, s2) \ + ((s1).sperm == (s2).sperm) + +/* qualifier object */ +struct __qualifier_ext { + id_t q_id; +}; + +struct qualifier_obj_tag { + obj_prefix o_prefix; + struct __qualifier_ext i; +}; + +#define qid i.q_id + +#define qualifier_obj_id(q) \ + ((q).qid) + +/* acl_entry object */ +struct __acl_entry { + acl_tag_t e_tag; + qualifier_obj e_id; + acl_permset_obj e_perm; +}; + +struct __acl_entry_ext { + acl_entry_obj *e_prev, *e_next; + acl_obj *e_container; + struct __acl_entry e_entry; +}; + +struct acl_entry_obj_tag { + obj_prefix o_prefix; + struct __acl_entry_ext i; +}; + +#define econtainer i.e_container +#define eprev i.e_prev +#define enext i.e_next +#define eentry i.e_entry +#define etag i.e_entry.e_tag +#define eperm i.e_entry.e_perm +#define eid i.e_entry.e_id + +#define init_acl_entry_obj(entry) do { \ + (entry).etag = ACL_UNDEFINED_TAG; \ + init_obj(acl_permset, (entry).eperm); \ + (entry).eperm.sperm = ACL_PERM_NONE; \ + init_obj(qualifier, (entry).eid); \ + (entry).eid.qid = ACL_UNDEFINED_ID; \ + } while(0) + +/* acl object */ +struct __acl_ext { + acl_entry_obj *a_prev, *a_next; + acl_entry_obj *a_curr; + size_t a_used; +}; +struct acl_obj_tag { + obj_prefix o_prefix; + struct __acl_ext i; +}; + +#define aprev i.a_prev +#define anext i.a_next +#define acurr i.a_curr +#define aused i.a_used + +/* external ACL representation */ +struct __acl { + size_t x_size; + struct __acl_entry x_entries[0]; +}; + +int __acl_reorder_obj_p(acl_entry_obj *acl_entry_obj_p); +acl_obj * __acl_init_obj(void); +acl_entry_obj * __acl_create_entry_obj(acl_obj *acl_obj_p); +void __acl_free_acl_obj(acl_obj *acl_obj_p); + +#define FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) \ + for( (entry_obj_p) = (acl_obj_p)->anext; \ + (entry_obj_p) != (acl_entry_obj *)(acl_obj_p); \ + (entry_obj_p) = (entry_obj_p)->enext ) + diff --git a/libacl/libobj.h b/libacl/libobj.h new file mode 100644 index 0000000..6fb6d6b --- /dev/null +++ b/libacl/libobj.h @@ -0,0 +1,87 @@ +#ifndef __LIBOBJ_H +#define __LIBOBJ_H + +#include <stdlib.h> + +/* Ugly pointer manipulation */ + +#ifdef LIBACL_DEBUG +# define ext2int(T, ext_p) \ + ((T##_obj *)__ext2int_and_check(ext_p, T##_MAGIC, #T)) +#else +# define ext2int(T, ext_p) \ + ((T##_obj *)__ext2int_and_check(ext_p, T##_MAGIC)) +#endif + +#define int2ext(int_p) \ + ((int_p) ? &(int_p)->i : NULL) +#define new_var_obj_p(T, sz) \ + ((T##_obj *)__new_obj_p(T##_MAGIC, sizeof(T##_obj) + sz)) +#define realloc_var_obj_p(T, p, sz) \ + ((T##_obj *)realloc(p, sizeof(T##_obj) + sz)) +#define new_obj_p(T) \ + new_var_obj_p(T, 0) +#define init_obj(T, o) \ + ((o).o_prefix.p_magic = T##_MAGIC) +#define check_obj_p(T, obj_p) \ + ((T##_obj *)__check_obj_p((obj_prefix *)(obj_p), T##_MAGIC)) +#define free_obj_p(obj_p) \ + (__free_obj_p((obj_prefix *)(obj_p))) + + +/* prefix for all objects */ +typedef struct { + int p_magic; +} obj_prefix; + +#define pmagic i.p_magic + +/* magic object values */ +#define acl_MAGIC (0x712C) +#define acl_entry_MAGIC (0x9D6B) +#define acl_permset_MAGIC (0x1ED5) +#define qualifier_MAGIC (0x1C27) +#define string_MAGIC (0xD5F2) +#define cap_MAGIC (0x6CA8) + +/* object types */ +struct string_obj_tag; +typedef struct string_obj_tag string_obj; + +/* string object */ +struct __string_ext { + char s_str[0]; +}; +struct string_obj_tag { + obj_prefix o_prefix; + struct __string_ext i; +}; + +#define sstr i.s_str + +/* object creation, destruction, conversion and validation */ +void * +__new_obj_p( + int magic, + size_t size); +void +__free_obj_p( + obj_prefix *obj_p); +obj_prefix * +__check_obj_p( + obj_prefix *obj_p, + int magic); +#ifdef LIBACL_DEBUG +obj_prefix * +__ext2int_and_check( + void *ext_p, + int magic, + const char *typename); +#else +obj_prefix * +__ext2int_and_check( + void *ext_p, + int magic); +#endif + +#endif /* __LIBOBJ_H */ diff --git a/man/Makefile b/man/Makefile index e69de29..18eb208 100644 --- a/man/Makefile +++ b/man/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +SUBDIRS = man1 man5 + +default install install-dev install-lib: $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) diff --git a/man/man1/Makefile b/man/man1/Makefile index e69de29..a3408d2 100644 --- a/man/man1/Makefile +++ b/man/man1/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 1 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev install-lib: diff --git a/man/man1/getfacl.1 b/man/man1/getfacl.1 index e69de29..bae7e67 100644 --- a/man/man1/getfacl.1 +++ b/man/man1/getfacl.1 @@ -0,0 +1,146 @@ +.\" Access Control Lists manual pages +.\" +.\" (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org> +.\" +.\" This manual page may used unter the terms of the GNU LGPL license, either +.\" version 2 of this license, or (at your option) any later version. +.\" +.fam T +.TH GETFACL 1 "ACL File Utilities" "May 2000" "Access Control Lists" +.SH NAME +getfacl \- get file access control lists +.SH SYNOPSIS + +.B getfacl +[\-adRLPvh] file ... + +.B getfacl +[\-adRLPvh] - + +.SH DESCRIPTION +For each file, getfacl displays the file name, owner, the group, +and the Access Control List (ACL). If a directory has a default ACL, +getfacl also displays the default ACL. Non-directories cannot have default ACLs. + +If getfacl is used on a file system that does not support ACLs, getfacl +displays the access permissions defined by the traditional file mode permission +bits. + +The output format of getfacl is as follows: +.fam C +.RS +.nf + 1: # file: somedir/ + 2: # owner: lisa + 3: # group: staff + 4: user::rwx + 5: user:joe:rwx #effective:r-x + 6: group::rwx #effective:r-x + 7: group:cool:r-x + 8: mask:r-x + 9: other:r-x +10: default:user::rwx +11: default:user:joe:rwx #effective:r-x +12: default:group::r-x +13: default:mask:r-x +14: default:other:--- + +.fi +.RE +.fam T + +Lines 4, 6 and 9 correspond to the user, group and other fields of +the file mode permission bits. These three are called the base ACL +entries. Lines 5 and 7 are named user and named group entries. Line 8 is +the effective rights mask. This entry limits the effective rights granted +to all groups and to named users. (The file owner and others permissions +are not affected by the effective rights mask; all other entries are.) +Lines 10--14 display +the default ACL associated with this directory. Directories may +have a default ACL. Regular files never have a default ACL. + +The default behavior for getfacl is to display both the ACL and the +default ACL, and to include an effective rights comment for lines +where the rights of the entry differ from the effective rights. + +If output is to a terminal, the effective rights comment is aligned to +column 40. Otherwise, a single tab character separates the ACL entry +and the effective rights comment. + +The ACL listings of multiple files are separated by blank lines. +The output of getfacl can also be used as input to setfacl. + +.SS PERMISSIONS +Process with search access to a file (i.e., processes with read access +to the containing directory of a file) are also granted read access +to the file's ACLs. This is analogous to the permissions required for +accessing the file mode. + +.SS OPTIONS +.TP 4 +.I -a, --access +Display the file access control list. +.TP +.I -d, --default +Display the default access control list. +.TP +.I --omit-header +Do not display the comment header (the first three lines of each file's output). +.TP +.I --all-effective +Print all effective rights comments, even if identical to the rights defined by the ACL entry. +.TP +.I --no-effective +Do not print effective rights comments. +.TP +.I --skip-base +Skip files that only have the base ACL entries (owner, group, others). +.TP +.I -R, --recursive +List the ACLs of all files and directories recursively. +.TP +.I --post-order +List the ACLs of all files and directories recursively, and process the directory tree in post-order (directories are processed after their children are processed). This option most probably is unnecessary and was added for completeness only. +.TP +.I -L, --logical +Logical walk, follow symbolic links. The default behavior is to follow +symbolic link arguments, and to skip symbolic links encountered in +subdirectories. +.TP +.I -P, --physical +Physical walk, skip all symbolic links. This also skips symbolic link +arguments. +.TP +.I --tabular +Use an alternative tabular output format. The ACL and the default ACL are displayed side by side. Permissions that are ineffective due to the ACL mask entry are displayed capitalized. The entry tag names for the ACL_USER_OBJ and ACL_GROUP_OBJ entries are also displayed in capital letters, which helps in spotting those entries. +.TP +.I --absolute-names +Do not strip leading slash characters (`/'). The default behavior is to +strip leading slashes, so that an ACL listing can be easily applied to a +different directory sub-tree. +.TP +.I -v, --version +Print the version of getfacl and exit. +.TP +.I -h, --help +Print help explaining the command line options. +.TP +.I -- +End of command line options. All remaining parameters are interpreted as file names, even if they start with a dash character. +.TP +.I - +If the file name parameter is a single dash character, getfacl reads a list of files from standard input. + +.SH CONFORMANCE TO POSIX 1003.1e DRAFT STANDARD 17 +If the environment variable POSIXLY_CORRECT is defined, the default behavior of getfacl changes in the following ways: Unless otherwise specified, only the ACL is printed. The default ACL is only printed if the +.I -d +option is given. If no command line parameter is given, +.I getfacl +behaves as if it was invoked as ``getfacl -''. +.SH AUTHOR +Andreas Gruenbacher, +.RI < a.gruenbacher@computer.org >. + +Please send your bug reports and comments to the above address. +.SH SEE ALSO +.BR setfacl "(1), " acl (5) diff --git a/man/man1/setfacl.1 b/man/man1/setfacl.1 index e69de29..2a1dabb 100644 --- a/man/man1/setfacl.1 +++ b/man/man1/setfacl.1 @@ -0,0 +1,316 @@ +.\" Access COntrol Lists manual pages +.\" +.\" (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org> +.\" +.\" This manual page may used unter the terms of the GNU LGPL license, either +.\" version 2 of this license, or (at your option) any later version. +.\" +.fam T +.TH SETFACL 1 "ACL File Utilities" "May 2000" "Access Control Lists" +.SH NAME +setfacl \- set file access control lists +.SH SYNOPSIS + +.B setfacl +[-bkndRLPvh] [ [{-s|-m|-x} acl_spec ...] file ... ] ... + +.B setfacl +[-bkndRLPvh] [ [{-S|-M|-X} acl_file ...] file ... ] ... + +.B setfacl +[-t] -B file + +.SH DESCRIPTION +This utility sets Access Control Lists (ACLs) of files and directories. +On the command line, a sequence of commands is followed by a sequence of +files (which in turn can be followed by another sequence of commands, ...). + +The options +.I -s, -m, +and +.I -x +expect an ACL on the command line. Multiple ACL entries are separated +by comma characters (`,'). The options +.I -S, -M, +and +.I -X +read an ACL from a file or from standard input. The ACL entry format is described in Section +ACL ENTRIES. + +The +.IR "-s (--set)" " and " "-S (--set-file)" +options set the ACL of a file or a directory. The previous ACL is +replaced. +ACL entries for this operation must include permissions. + +The +.IR "-m (--modify)" " and " "-M (--modify-file)" +options modify the ACL of a file or directory. +.\".I Absolute +.\"as well as +.\".I relative +.\"ACL entries are accepted as parameters. +ACL entries for this operation must include permissions. + +The +.IR "-x (--remove)" " and " "-X (--remove-file)" +options remove ACL enries. Only +ACL entries without the +.I perms +field are accepted as parameters, unless POSIXLY_CORRECT is defined. + +When reading from files using the +.I -S, -M, +and +.IR -X +options, setfacl accepts a superset of the output getfacl produces. +There is at most one ACL entry per line. After a Pound sign (`#'), +everything up to the end of the line is treated as a comment. + +If setfacl is used on a file system which does not support ACLs, setfacl +operates on the file mode permission bits. If the ACL does not fit completely +in the permission bits, setfacl modifies the file mode permission bits to reflect the ACL as closely as possible, writes an error message to standard error, and returns with an exit status greater than 0. + +.SS PERMISSIONS +The file owner and processes capable of CAP_FOWNER are granted the right +to modify ACLs of a file. This is analogous to the permissions required +for accessing the file mode. (On current Linux systems, root is the only +user with the CAP_FOWNER capability.) + +.SS OPTIONS +.TP 4 +.I -b, --remove-all +Remove all extended ACL entries. The base ACL entries of the owner, group and others are retained. +.TP 4 +.I -k, --remove-default +Remove the Default ACL. If no Default ACL exists, no warnings are issued. +.TP 4 +.I -n, --no-mask +Do not recalculate the effective rights mask. The default behavior of +setfacl is to recalculate the ACL mask entry, unless a mask entry was explicitly given. +The mask entry is set to the union of all permissions of the owning group, and all named user and group entries. (These are exactly the entries affected by the mask entry). +.TP 4 +.I --mask +Do recalculate the effective rights mask, even if an ACL mask entry was explicitly given. (See the +.IR "-n " option.) +.TP 4 +.I -d, --default +All operations apply to the Default ACL. Regular ACL entries in the +input set are promoted to Default ACL entries. Default ACL entries in +the input set are discarded. (A warning is issued if that happens). +.TP 4 +.I --restore +Restore a permission backup created by `getfacl -R' or similar. All permissions +of a complete directory subtree are restored using this mechanism. If the input +contains owner comments or group comments, and setfacl is run by root, the +owner and owning group of all files are restored as well. This option cannot be mixed with other options except `-t'. +.TP 4 +.I --test +Test mode. Instead of changing the ACLs of any files, the resulting ACLs are listed. +.TP 4 +.I -R, --recursive +Apply operations to all files and directories recursively. This option cannot be mixed with `--restore'. +.TP 4 +.I --post-order +Apply operations to all files and directories recursively. Traverse subdirectories in post-order (directories are processed after their children are processed). This option cannot be mixed with `--restore'. +.TP 4 +.I -L, --logical +Logical walk, follow symbolic links. The default behavior is to follow symbolic link arguments, and to skip symbolic links encountered +in subdirectories. This option cannot be mixed with `--restore'. +.TP 4 +.I -P, --physical +Physical walk, skip all symbolic links. This also skips symbolic link arguments. +This option cannot be mixed with `--restore'. +.TP 4 +.I -v, --version +Print the version of setfacl and exit. +.TP 4 +.I -h, --help +Print help explaining the command line options. +.TP 4 +.I -- +End of command line options. All remaining parameters are interpreted as file names, even if they start with a dash. +.TP 4 +.I - +If the file name parameter is a single dash, setfacl reads a list of files from standard input. + +.SS ACL ENTRIES +The setfacl utility recognizes the following ACL entry formats (blanks +inserted for clarity): + +.fam C +.TP +.\".RI "[d[efault]:] [u[ser]:]" "uid " [:[+|^] perms ] +.RI "[d[efault]:] [u[ser]:]" "uid " [: perms ] +.fam T +Permissions of a named user. Permissions of the file owner if +.I uid +is empty. +.fam C +.TP +.\".RI "[d[efault]:] g[roup]:" "gid " [:[+|^] perms ] +.RI "[d[efault]:] g[roup]:" "gid " [: perms ] +.fam T +Permissions of a named group. Permissions of the owning group if +.I gid +is empty. +.fam C +.TP +.\".RI "[d[efault]:] m[ask] [:[+|^]" " perms " ] +.RI "[d[efault]:] m[ask] [:" perms ] +.fam T +Effective rights mask +.fam C +.TP +.\".RI "[d[efault]:] o[ther] [:[+|^]" " perms" ] +.RI "[d[efault]:] o[ther] [:" perms ] +.fam T +Permissions of others. +.PP +Whitespace between delimiter characters and non-delimiter characters is ignored. +.PP +.\"An ACL entry is called +.\".I absolute +.\"here if it contains the +.\".I perms +.\"field. +.\"It is +.\".I relative +.\"if it includes one of the modifiers `+' or '^' and the +.\".I perms +.\"field. +.PP +Proper ACL entries including permissions are used in modify and set operations. (options +.IR -m ", " -M ", " -s " and " -S ). +.\".I Relative +.\"entries may only be used in modify operations (options +.\".IR -m " and " -M ). +Entries without the +.I perms +field are used for +.I deletion +of entries (options +.IR -x " and " -X ). +.PP +For +.I uid +and +.I gid +you can specify either a name or a number. The +.I perms +field can be a combination of the characters +.IR r ", " w ", " x ", " \- , +or an octal digit (0-7). + +.SS AUTOMATICALLY CREATED ENTRIES +Initially, files and directories contain only the three base ACL entries +for the owner, the group, and others. There are some rules that +need to be satisfied in order for an ACL to be valid: +.IP \(bu 4 +The three base entries cannot be removed. There must be exactly one +entry of each of these base entry types. +.IP \(bu 4 +Whenever an ACL contains named user entries or named group objects, +it must also contain an effective rights mask. +.IP \(bu 4 +Whenever an ACL contains any Default ACL entries, the three Default ACL +base entries (default owner, default group, and default others) must also exist. +.IP \(bu 4 +Whenever a Default ACL contains named user entries or named group objects, +it must also contain a default effective rights mask. +.PP +To help the user ensure these rules, setfacl creates entries from existing +entries under the following conditions: +.IP \(bu 4 +If an ACL contains named user or named group entries, and +no mask entry exists, a mask entry containing the same permissions as +the group entry is created. Unless the +.I -n +option is given, the permissions of the mask entry are further adjusted to include the union of all permissions affected by the mask entry. (See the +.I -n +option description). +.IP \(bu 4 +If a Default ACL entry is created, and the Default ACL contains no +owner, owning group, or others entry, a copy of the ACL owner, owning group, or others entry is added to the Default ACL. +.IP \(bu 4 +If a Default ACL contains named user entries or named group entries, and no mask entry exists, a mask entry containing the same permissions as the default Default ACL's group entry is added. Unless the +.I -n +option is given, the permissions of the mask entry are further adjusted to inclu +de the union of all permissions affected by the mask entry. (See the +.I -n +option description). +.PP +.SH EXAMPLES +Replacing the ACL of a file +.RS +.fam C +setfacl -s u::rw,g::r,o:-,g:staff:rw file +.fam T +.RE +.PP +Granting an additional user read access +.RS +.fam C +setfacl -m u:lisa:r file +.fam T +.RE +.\".PP +.\"Adding write access to the permissions of a user +.\".RS +.\".fam C +.\"setfacl -m u:lisa:+w file +.\".fam T +.\".RE +.PP +Revoking write access from all groups and all named users (using the effective rights mask) +.RS +.fam C +setfacl -m m:rx file +.fam T +.RE +.PP +Removing a named group entry from a file's ACL +.RS +.fam C +setfacl -x g:staff file +.fam T +.RE +.PP +Copying the ACL of one file to another +.RS +.fam C +getfacl file1 | setfacl -S- file2 +.fam T +.RE +.PP +Copying the access ACL into the Default ACL +.RS +.fam C +getfacl -a dir | setfacl -d -M- dir +.fam T +.RE +.PP +Copying a directory subtree; copying all ACLs from one subtree to the other (using the +.I bash +shell) +.RS +.fam C +cp -r dir1 dir2 && (cd dir1 && getfacl -R .) | \\ + (cd dir2 && setfacl -restore=-) +.fam T +.RE +.SH CONFORMANCE TO POSIX 1003.1e DRAFT STANDARD 17 +If the environment variable POSIXLY_CORRECT is defined, the default behavior of setfacl changes as follows: All non-standard options are disabled. +The ``default:'' prefix is disabled. +.\"Relative ACL entries (``+'' and ``^'' modifiers) are disabled. +The +.IR -x " and " -X +options also accept permissions (and ignore them). +.SH AUTHOR +Andreas Gruenbacher, +.RI < a.gruenbacher@computer.org >. + +Please send your bug reports, suggested features and comments to the +above address. +.SH SEE ALSO +.BR getfacl "(1), " chmod "(1), " umask "(1), " acl (5) diff --git a/man/man5/Makefile b/man/man5/Makefile index e69de29..cdda319 100644 --- a/man/man5/Makefile +++ b/man/man5/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 5 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev install-lib: diff --git a/man/man5/acl.5 b/man/man5/acl.5 index e69de29..475552d 100644 --- a/man/man5/acl.5 +++ b/man/man5/acl.5 @@ -0,0 +1,269 @@ +.\" +.\" Access Control Lists +.\" +.\" Documentation for the Linux implementation +.\" (C) Andreas Gruenbacher, 1999 +.\" +.TH ACL 5 "Access Control Lists" "Sep 1999" "Access Control Lists" +.SH NAME +acl - Access Control Lists +.SH DESCRIPTION +This document describes Posix-style access control lists as implemented under +Linux. Access control lists (ACLs) are used to define access to files +and directories. + +In portable programs, the Posix 1003.1e Draft Standard 17 library +functions should be used for mainpulating ACL. On most platforms, the +ACL entry manipulation functions are not available, so relying only on +the ACL manipulation and format conversion functions (ACL to and from +text format) is more portable. The library functions are declared in +the +.I sys/acl.h +header file. + +.SH ACCESS CONTROL LIST ENTRIES +An access control list contains a number of entries of various types. Each entry stands for permissions granted to a user, or to a group of users. +.PP +An ACL may contain entries with the following entry tag types. +.PP +.RS +.fam C +.nf +ACL_USER_OBJ (owner) +ACL_USER (named user) +ACL_GROUP_OBJ (owning group) +ACL_GROUP (named group) +ACL_MASK (effective rights mask) +ACL_OTHER (other users) +.fi +.fam T +.RE +.PP +The +ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER entries +correspond to the traditional file mode permission bits. There is +exactly one each of these entries in a valid ACL. +.PP +ACL_USER and ACL_GROUP +entries define explicit rights for users and groups, respectively. For +entries of these two types, +.I a_id[0] +is set to the ID of the user or group in question. Whenever there are +any entries of the last two types in the ACL, an ACL_MASK +entry is also required. + +An ACL_MASK entry limits the effective rights granted +to named users or groups. The efective rights granted are those +that are both granted by the user's or group's entry, and by the ACL_MASK entry. The ACL_MASK entry does not apply to the ACL_USER_OBJ and ACL_OTHER entries. +.PP +The lowest three bits of +.I a_perm +define the rights granted to the user the entry applies to, just like +the bits in the traditional file mode. This results in a value between 0 and 7 +(from 0 standing for no access to 7 standing for read, write, and execute access). For accessing these bits, the constants ACL_READ, ACL_WRITE and ACL_EXECUTE should be used. + +.SH VALID ACCESS CONTROL LISTS +Each valid ACL has as a minimum the three required base entries +ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER. These entries correspond +to the traditional Posix permission bits. There must be exactly one each +of these three entries. The permission mask `rw-r-----' corresponds to the +following entries: +.sp +.RS +.fam C +.nf + u::rw- (ACL_USER_OBJ entry) + g::r-- (ACL_GROUP_OBJ entry) + o:--- (ACL_OTHER entry) +.fi +.fam T +.RE +.PP +An ACL must also contain exactly one ACL_MASK entry, if it contains +additional ACL_USER or ACL_GROUP entries. For each user or group, there +must be at most one ACL_USER or ACL_GROUP entry per access control list. An ACL may also contain an ACL_MASK entry if no ACL_USER or ACL_GROUP entries exist. +.sp +.RS +.fam C +.nf + u:joe:rw- (ACL_USER entry) + g:webteam:rw- (ACL_GROUP entry) + m:rw- (ACL_MASK entry) +.fi +.fam T +.RE +.PP +.SS THE ACL_MASK ENTRY +The purpose of the ACL_MASK entry is to limit +the effective rights granted to groups and named users in +the ACL. The effective rights granted to a user or a group with an ACL_USER +or an ACL_GROUP entry are those which are listed in both the ACL_USER +or ACL_GROUP entry +.I and +the ACL_MASK entry. The ACL_USER_OBJ and ACL_OTHER entries +are not affected by the ACL_MASK entry. + +.SH PERMISSIONS +The permissions required for manipulating ACLs of an inode are similar +to the permissions required for manipulating the file mode. Processes +with search access to a file are granted the right to read ACLs. Only the +file owner and processes capable of CAP_FOWNER are granted the right to +modify ACLs. (On current Linux systems, root is the only user with the +CAP_FOWNER capability.) + +.SH DETERMINING ACCESS +When a process requests access to a file, the following algorithm determines whether access is granted or not. The input to the algorithm is a set of requested permissions (read, write, execute). + +.SS (1) "Find a matching ACL entry" +.IP \(bu 4 +If the user is the file owner, access is granted \fIonly\fR if the +ACL_USER_OBJ entry contains the requested permissions. +.IP \(bu 4 +If the ACL contains a named user (ACL_USER) entry that matches the user, then: +.RS +.\".IP \(bu 4 +.IP - 4 +If access is granted by that entry, continue with step \fB(2)\fR below. +.\".IP \(bu 4 +.IP - 4 +Otherwise, access is denied. +.RE +.IP \(bu 4 +If the user is in the owning group of the file (ACL_GROUP_OBJ entry), or if the user is member of a named group (ACL_GROUP entries), then: +.RS +.\".IP \(bu 4 +.IP - 4 +If either the ACL_GROUP_OBJ entry or one of the ACL_GROUP entries contains the requested permissions, continue with step \fB(2)\fR below. (Permissions of multiple ACL entries are +.I not +accumulated.) +.\".IP \(bu 4 +.IP - 4 +Otherwise, access is denied. +.RE +.IP \(bu 4 +If none of the above rules match, then +.RS +.\".IP \(bu 4 +.IP - 4 +If the ACL_OTHER entry contains the requested permissions, access is +granted. +.\".IP \(bu 4 +.IP - 4 +Otherwise, access is denied. +.RE +.SS (2) Check the access mask +.IP \(bu 4 +If the access mask (ACL_MASK) contains the requested permissions, access is granted. +.IP \(bu 4 +Otherwise, access is denied. +.SH DEFAULT ACCESS CONTROL LISTS +Directories may have a default ACL, in addition to the regular ACL. While the +purpose of the regular ACL is to control access to a file or directory, +the purpose of the default ACL is to control access to files which are +created inside the directory. +.PP +When a file is created, +a create permissions are specified that determines the maximum access rights to +the file. This usually is 0666 of files, and 0777 for directories. +.PP +Traditionally, the effective access rights to new files are determined by combining the +.B umask +and the create permissions. The default ACL replaces the role of the +.BR umask . +The following steps are taken when a file is created inside a directory which has a default ACL: +.IP \(bu 4 +The new file inherits the directory's default ACL as its access ACL. +.IP \(bu 4 +The permissions of the new file's access ACL are modified in the following way: +.RS +.IP \(bu 4 +The ACL_USER entry is set to the union of the value determied by the default ACL and the user bits of the create permissions. +.IP \(bu 4 +The ACL_OTHER entry is set to the union of the value determined by the default ACL and the other bits of the create permissions. +.IP \(bu 4 +If the new file's ACL contains an ACL_MASK entry, the permission bits of the ACL_MASK entry are set to the group bits of the create permissions. If the new file's ACL does not contain an ACL_MASK entry, the permission bits of the ACL_GROUP_OBJ entry are set to the group bits of the create permissions. +.RE +.IP \(bu 4 +The user and other part of the new file's mode bits are set to the ACL_USER_OBJ and ACL_OTHER permission bits, respectively. +.IP \(bu 4 +If the new file's ACL contains an ACL_MASK entry, the group bits of the new file's mode field are set to the ACL_MASK entry permission bits. If the new file's ACL does not contain an ACL_MASK entry, the group bits of the new file's mode field are set to the ACL_GROUP_OBJ entry permission bits. +.IP \(bu 4 +If the new file is a directory, it inherits the parent directory's default ACL as its own default ACL. +.PP +For directories without a default ACL, the +.B umask +is used to determine effective permissions (see +.BR umask (2)). +.PP +.SH FILE MODE PERMISSION BITS TO ACL ENTRY MAPPING +.fam C +.nf + user group other + ----+-------+-------+-------+ + | r w x | r w x | r w x | + ----+-------+-------+-------+ + ^ ^ ^ + | | +-- maps to ACL_OTHER + | +-- maps to ACL_GROUP_OBJ or ACL_MASK + +-- maps to ACL_USER_OBJ +.fi +.fam T +.PP +.SH NFSv2, NFSv3 AND ACCESS CONTROL LISTS +The NFS protocol in version 2 performs some access control decisions at +the client, based on the file mode permission bits. It serves the user +cached file contents if it thinks access would be granted. This logic +is no longer correct if access control lists are in effect. Both false +positives and denials might result. + +As a workaround, the file mode permission bits are modified before +sending them to NFSv2 clients. This ensures NFS clients don't grant +extra permissions. (Only the kernel NFS daemon does that right now; the +userspace NFS daemon has not been patched yet.) The file mode permission +sent are a subset of the real file mode permission bits. They are changed +as follows: + +.IP \(bu 4 +The group file mode permission bits are set to the intersection of the ACL_GROUP_OBJ and the ACL_MASK ACL entry. +.IP \(bu 4 +The others file mode permission bits are set to the intersection of all +ACL entries excluding the ACL_USER_OBJ entry. +.PP +A consequence of these changes is that extended permissions granted by ACLs are not available over NFSv2 mounts. + +Up to at least 2.2.18 and 2.4.2 kernels, the NFSv3 implementation does +not implement the ACCESS remote procedure call. Therefore, NFSv3 currently +suffers the same problems as NFSv2. The same workaround is employed right +now. + +.SH CHANGES TO THE FILE UTILITIES +The +.BR ls (1) +utility displays a plus sign (`+') after the permission string of entries with an extended ACL (i.e., entries where the permission string shows only part of the effective permissions). +.PP +The +.BR cp "(1) and " mv (1) +utilities preserve ACLs if possible. If files are copied or moved between fileystems that do not support ACLs, only the file mode permission bits are preserved, and a warning is written to standard error. +.PP +The +.BR chmod (1) +utility is traditionally used to change the file mode permission bits. +Changing the permission bits using +.B chmod +has the following effect on an ACL that is associated with a file: +.IP \(bu 4 +The new user permission bits replace the permissions of the owner ACL entry. +.IP \(bu 4 +The new group permission bits replace the permission bits of the mask ACL entry if a mask ACL entry exists. The new group permission bits replace the permission bits of the owning group ACL entry if no mask ACL entry exists. +.IP \(bu 4 +The new others permission bits replace the permissions of the others ACL entry. +.PP +.fam T +.SH AUTHOR +Andreas Gruenbacher, +.RI < a.gruenbacher@computer.org >. + +Please send your bug reports, suggested features and comments to the +above address. +.SH SEE ALSO +getfacl(1), setfacl(1), chmod(1), umask(1), ls(1) diff --git a/po/Make.rules b/po/Make.rules new file mode 100644 index 0000000..3f320a1 --- /dev/null +++ b/po/Make.rules @@ -0,0 +1,48 @@ +.PHONY : po + +LINGUAS := de +X_FILES := src/getfacl.c src/setfacl.c src/do_set.c libacl/acl_error.c + +all :: $(LINGUAS:%=po/%.mo) + +%.mo: %.po + @if test -n "$(MSGFMT)" ; then \ + echo "$(MSGFMT) -o $@ $<" ; \ + $(MSGFMT) -o $@ $< ; \ + else \ + rm -f $@ ; \ + fi + +# xgettext doesn't process C preprocessor statements correctly +# in the version I have, so... + +po :: + ( for F in $(X_FILES) ; do \ + cpp -I. $$F ; done ) | \ + xgettext --omit-header --language=C -o po/acl.pot - + for CC in $(LINGUAS) ; do \ + msgmerge -o po/$$CC.po po/$$CC.po po/acl.pot ; \ + done + +clean :: + rm -f $(LINGUAS:%=po/%.mo) + +distclean :: + rm -f $(LINGUAS:%=po/%.mo) + +install :: + @for CC in $(LINGUAS) ; do \ + if test -e po/$$CC.mo ; then \ + TO_DIR=$(ROOT)$(gnulocaledir)/$$CC/LC_MESSAGES ; \ + TO_FILE=$$TO_DIR/$(PACKAGE).mo ; \ + $(INSTALL) -d $$TO_DIR ; \ + $(INSTALL) -m 644 po/$$CC.mo $$TO_FILE ; \ + fi ; \ + done + +uninstall :: + @for CC in $(LINGUAS) ; do \ + TO_FILE=$(ROOT)$(gnulocaledir)/$$CC/LC_MESSAGES/$(PACKAGE).mo ; \ + echo $$TO_FILE ; \ + rm -f $$TO_FILE ; \ + done diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..9af6b93 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,11 @@ +# List of source files containing translatable strings. +# Copyright (C) Andreas Gruenbacher, <ag@computer.org> + +# Libacl library files +libacl/acl_error.c + +# Package source files +src/getfacl.c +src/setfacl.c +src/do_set.c + diff --git a/po/acl.pot b/po/acl.pot new file mode 100644 index 0000000..d579e76 --- /dev/null +++ b/po/acl.pot @@ -0,0 +1,155 @@ +#, c-format +msgid "%s: Removing leading '/' from absolute path names\n" +msgstr "" + +#, c-format +msgid "%s %s -- get file access control lists\n" +msgstr "" + +#, c-format +msgid "Usage: %s [-%s] file ...\n" +msgstr "" + +msgid " -d, --default display the default access control list\n" +msgstr "" + +msgid "" +" -a, --access display the file access control list only\n" +" -d, --default display the default access control list only\n" +" --omit-header do not display the comment header\n" +" --all-effective print all effective rights\n" +" --no-effective print no effective rights\n" +" --skip-base skip files that only have the base entries\n" +" -R, --recursive recurse into subdirectories\n" +" --post-order visit subdirectories first\n" +" -L, --logical logical walk, follow symbolic links\n" +" -P --physical physical walk, do not follow symbolic links\n" +" --tabular use tabular output format\n" +" --absolute-names don't strip leading '/' in pathnames\n" +msgstr "" + +msgid "" +" -v, --version print version and exit\n" +" -h, --help this help text\n" +msgstr "" + +#, c-format +msgid "%s: Standard input: %s\n" +msgstr "" + +#, c-format +msgid "Try `%s -h' for more information.\n" +msgstr "" + +#, c-format +msgid "%s: %s: No filename found in line %d, aborting\n" +msgstr "" + +#, c-format +msgid "%s: No filename found in line %d of standard input, aborting\n" +msgstr "" + +#, c-format +msgid "%s: %s: %s in line %d\n" +msgstr "" + +#, c-format +msgid "%s: %s: Cannot change owner/group: %s\n" +msgstr "" + +#, c-format +msgid "%s %s -- set file access control lists\n" +msgstr "" + +#, c-format +msgid "Usage: %s %s\n" +msgstr "" + +msgid "" +" -s, --set=acl set the ACL of file(s), replacing the current ACL\n" +" -S, --set-file=file read ACL entries to set from file\n" +msgstr "" + +msgid "" +" -m, --modify=acl modify the current ACL(s) of file(s)\n" +" -M, --modify-file=file read ACL entries to modify from file\n" +" -x, --remove=acl remove entries from the ACL(s) of file(s)\n" +" -X, --remove-file=file read ACL entries to remove from file\n" +" -b, --remove-all remove all extended ACL entries\n" +" -k, --remove-default remove the default ACL\n" +msgstr "" + +msgid " --mask do recalculate the effective rights mask\n" +msgstr "" + +msgid "" +" -n, --no-mask don't recalculate the effective rights mask\n" +" -d, --default operations apply to the default ACL\n" +msgstr "" + +msgid "" +" -R, --recursive recurse into subdirectories\n" +" --post-order visit subdirectories first\n" +" -L, --logical logical walk, follow symbolic links\n" +" -P, --physical physical walk, do not follow symbolic links\n" +" --restore=file restore ACLs (inverse of `getfacl -R')\n" +" --test test mode (ACLs are not modified)\n" +msgstr "" + +msgid "[-bkndRLPvh] { -s|-S|-m|-M|-x|-X ... } file ..." +msgstr "" + +msgid "[-bkndvh] {-m|-M|-x|-X ... } file ..." +msgstr "" + +#, c-format +msgid "%s: Option -%c incomplete\n" +msgstr "" + +#, c-format +msgid "%s: Option -%c: %s near character %d\n" +msgstr "" + +#, c-format +msgid "%s: %s in line %d of file %s\n" +msgstr "" + +#, c-format +msgid "%s: %s in line %d of standard input\n" +msgstr "" + +msgid "# (empty acl)\n" +msgstr "" + +msgid "# (acl unchanged)\n" +msgstr "" + +msgid "# (empty default acl)\n" +msgstr "" + +msgid "# (default acl unchanged)\n" +msgstr "" + +#, c-format +msgid "%s: %s: Resulting ACL `%s': %s at entry %d\n" +msgstr "" + +#, c-format +msgid "%s: %s: Resulting default ACL `%s': %s at entry %d\n" +msgstr "" + +#, c-format +msgid "%s: %s: Only directories can have a default ACL\n" +msgstr "" + +msgid "Multiple entries" +msgstr "" + +msgid "Duplicate entries" +msgstr "" + +msgid "Missing or wrong entry" +msgstr "" + +msgid "Invalid entry type" +msgstr "" diff --git a/po/de.mo b/po/de.mo Binary files differnew file mode 100644 index 0000000..4479857 --- /dev/null +++ b/po/de.mo diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000..9ae1934 --- /dev/null +++ b/po/de.po @@ -0,0 +1,189 @@ +# German translation for ACL utilities +# Copyright (C) 2000 Free Software Foundation, Inc. +# Andreas Grünbacher <a.gruenbacher@computer.org>, 2000. +# +#, c-format +msgid "%s: Removing leading '/' from absolute path names\n" +msgstr "%s: Entferne führenden '/' von absoluten Pfadnamen\n" + +#, c-format +msgid "%s %s -- get file access control lists\n" +msgstr "%s %s -- Datei-Zugriffskontrollisten (ACLs) anzeigen\n" + +#, c-format +msgid "Usage: %s [-%s] file ...\n" +msgstr "Aufruf: %s [-%s] datei ...\n" + +msgid " -d, --default display the default access control list\n" +msgstr " -d, --default Die Default-ACL ausgeben\n" + +msgid "" +" -a, --access display the file access control list only\n" +" -d, --default display the default access control list only\n" +" --omit-header do not display the comment header\n" +" --all-effective print all effective rights\n" +" --no-effective print no effective rights\n" +" --skip-base skip files that only have the base entries\n" +" -R, --recursive recurse into subdirectories\n" +" --post-order visit subdirectories first\n" +" -L, --logical logical walk, follow symbolic links\n" +" -P --physical physical walk, do not follow symbolic links\n" +" --tabular use tabular output format\n" +" --absolute-names don't strip leading '/' in pathnames\n" +msgstr "" +" -a, --access Nur die ACL ausgeben\n" +" -d, --default Nur die Default-ACL ausgeben\n" +" --omit-header Keine Datei-Kommentare ausgeben\n" +" --all-effective Alle Effektivrechte-Kommentare ausgeben\n" +" --no-effective Keine Effektivrechte-Kommentare ausgeben\n" +" --skip-base Überspringe Dateien mit Basiseinträgen\n" +" -R, --recursive In Unterverzeichnisse wechseln\n" +" --post-order Unterverzeichnisse zuerst besuchen\n" +" -L, --logical Symbolische Links verfolgen\n" +" -P, --physical Symbolische Links nicht verfolgen\n" +" --tabular Tabellarisches Ausgabeformat verwenden\n" +" --absolute-names Führende '/' in Pfadnamen nicht entfernen\n" + +msgid "" +" -v, --version print version and exit\n" +" -h, --help this help text\n" +msgstr "" +" -v, --version Nur die Version ausgeben\n" +" -h, --help Diese Hilfe\n" + +#, c-format +msgid "%s: Standard input: %s\n" +msgstr "%s: Standardeingabe: %s\n" + +#, c-format +msgid "Try `%s -h' for more information.\n" +msgstr "Weiterführende Informationen mit `%s -h'.\n" + +#, c-format +msgid "%s: %s: No filename found in line %d, aborting\n" +msgstr "%s: %s: Kein Dateiname gefunden in Zeile %d; Abbruch\n" + +#, c-format +msgid "%s: No filename found in line %d of standard input, aborting\n" +msgstr "%s: Kein Dateiname gefunden in Zeile %d der Standardeingabe; Abbruch\n" + +#, c-format +msgid "%s: %s: %s in line %d\n" +msgstr "%s: %s: %s in Zeile %d\n" + +#, c-format +msgid "%s: %s: Cannot change owner/group: %s\n" +msgstr "%s: %s: Kann Besitzer oder Gruppe nicht ändern: %s\n" + +#, c-format +msgid "%s %s -- set file access control lists\n" +msgstr "%s %s -- Datei-Zugriffskontrollisten (ACLs) ändern\n" + +#, c-format +msgid "Usage: %s %s\n" +msgstr "Verwendung: %s %s\n" + +msgid "" +" -s, --set=acl set the ACL of file(s), replacing the current ACL\n" +" -S, --set-file=file read ACL entries to set from file\n" +msgstr "" +" -s, --set=acl Ersetze die ACL(s) von Datei(en)\n" +" -S, --set-file=datei Lies die ACL-Einträge aus der Datei file\n" + +msgid "" +" -m, --modify=acl modify the current ACL(s) of file(s)\n" +" -M, --modify-file=file read ACL entries to modify from file\n" +" -x, --remove=acl remove entries from the ACL(s) of file(s)\n" +" -X, --remove-file=file read ACL entries to remove from file\n" +" -b, --remove-all remove all extended ACL entries\n" +" -k, --remove-default remove the default ACL\n" +msgstr "" +" -m, --modify=acl Verändere die ACL(s) von Dazei(en)\n" +" -M, --modify-file=datei Lies die ACL-Einträge aus der Datei file\n" +" -x, --remove=acl Entferne Einträge aus ACLs von Datei(en)\n" +" -X, --remove-file=datei Lies die ACL-Einträge aus der Datei file\n" +" -b, --remove-all Alle erweiterten ACL-Einträge entfernen\n" +" -k, --remove-default Default-ACL entfernen\n" + +msgid " --mask do recalculate the effective rights mask\n" +msgstr " --mask Effektive Rechte neu berechnen\n" + +msgid "" +" -n, --no-mask don't recalculate the effective rights mask\n" +" -d, --default operations apply to the default ACL\n" +msgstr "" +" --mask Effektive Rechte nicht neu berechnen\n" +" -d, --default Bearbeite die Default-ACL\n" + +msgid "" +" -R, --recursive recurse into subdirectories\n" +" --post-order visit subdirectories first\n" +" -L, --logical logical walk, follow symbolic links\n" +" -P, --physical physical walk, do not follow symbolic links\n" +" --restore=file restore ACLs (inverse of `getfacl -R')\n" +" --test test mode (ACLs are not modified)\n" +msgstr "" +" -R, --recursive In Unterverzeichnisse wechseln\n" +" --post-order Unterverzeichnisse zuerst besuchen\n" +" -L, --logical Symbolischen Links folgen\n" +" -P, --physical Symbolischen Links nicht folgen\n" +" --restore=datei ACLs wiederherstellen (Umkehr von `getfacl -R')\n" +" --test Testmodus (ACLs werden nicht verändert)\n" + +msgid "[-bkndRLPvh] { -s|-S|-m|-M|-x|-X ... } file ..." +msgstr "[-bkndRLPvh] { -s|-S|-m|-M|-x|-X ... } datei ..." + +msgid "[-bkndvh] {-m|-M|-x|-X ... } file ..." +msgstr "[-bkndvh] {-m|-M|-x|-X ... } datei ..." + +#, c-format +msgid "%s: Option -%c incomplete\n" +msgstr "%s: Option -%c unvollständig\n" + +#, c-format +msgid "%s: Option -%c: %s near character %d\n" +msgstr "%s: Option -%c: %s bei Zeichen %d\n" + +#, c-format +msgid "%s: %s in line %d of file %s\n" +msgstr "%s: %s in Zeile %d der Datei %s\n" + +#, c-format +msgid "%s: %s in line %d of standard input\n" +msgstr "%s: %s in Zeile %d der Standardeingabe\n" + +msgid "# (empty acl)\n" +msgstr "# (leere ACL)\n" + +msgid "# (acl unchanged)\n" +msgstr "# (ACL nicht verändert)\n" + +msgid "# (empty default acl)\n" +msgstr "# (leere Default-ACL)\n" + +msgid "# (default acl unchanged)\n" +msgstr "# (Default-ACL nicht verändert)\n" + +#, c-format +msgid "%s: %s: Resulting ACL `%s': %s at entry %d\n" +msgstr "%s: %s: Resultierende ACL `%s': %s bei Eintrag %d\n" + +#, c-format +msgid "%s: %s: Resulting default ACL `%s': %s at entry %d\n" +msgstr "%s: %s: Resultierende Default-ACL `%s': %s bei Eintrag %d\n" + +#, c-format +msgid "%s: %s: Only directories can have a default ACL\n" +msgstr "%s: %s: Nur Verzeichnisse können eine Default-ACL haben\n" + +msgid "Multiple entries" +msgstr "Mehrfache Einträge" + +msgid "Duplicate entries" +msgstr "Doppelte Einträge" + +msgid "Missing or wrong entry" +msgstr "Fehlende oder falsche Einträge" + +msgid "Invalid entry type" +msgstr "Ungültiger Eintragstyp" diff --git a/setfacl/Makefile b/setfacl/Makefile new file mode 100644 index 0000000..9bf138a --- /dev/null +++ b/setfacl/Makefile @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LTCOMMAND = setfacl +CFILES = setfacl.c do_set.c sequence.c parse.c user_group.c + +LCFLAGS = -DPKG_NAME=\"$(PKG_NAME)\" -DLOCALEDIR=\"$(gnulocaledir)\" +LLDLIBS = -lattr $(LIBACL) +LTDEPENDENCIES = $(LIBACL) + +default: $(LTCOMMAND) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_BIN_DIR) +install-dev install-lib: diff --git a/setfacl/do_set.c b/setfacl/do_set.c new file mode 100644 index 0000000..b86a1f2 --- /dev/null +++ b/setfacl/do_set.c @@ -0,0 +1,519 @@ +/* + File: set_operation.c + (Linux Access Control List Management) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <errno.h> +#include <sys/acl.h> +#include <acl/libacl.h> + +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> +#include <ftw.h> +#include "user_group.h" +#include "sequence.h" +#include "parse.h" + +#include <libintl.h> +#define _(String) gettext (String) + + +extern const char *progname; +extern int opt_recursive; +extern int opt_recalculate; +extern int opt_test; +extern int print_options; + +acl_entry_t +find_entry( + acl_t acl, + acl_tag_t type, + id_t id) +{ + acl_entry_t ent; + acl_tag_t e_type; + id_t *e_id_p; + + if (acl_get_entry(acl, ACL_FIRST_ENTRY, &ent) != 1) + return NULL; + + for(;;) { + acl_get_tag_type(ent, &e_type); + if (type == e_type) { + if (id != ACL_UNDEFINED_ID) { + e_id_p = acl_get_qualifier(ent); + if (e_id_p == NULL) + return NULL; + if (*e_id_p == id) { + acl_free(e_id_p); + return ent; + } + acl_free(e_id_p); + } else { + return ent; + } + } + if (acl_get_entry(acl, ACL_NEXT_ENTRY, &ent) != 1) + return NULL; + } +} + + +int +clone_entry( + acl_t from_acl, + acl_tag_t from_type, + acl_t *to_acl, + acl_tag_t to_type) +{ + acl_entry_t from_entry, to_entry; + from_entry = find_entry(from_acl, from_type, ACL_UNDEFINED_ID); + if (from_entry) { + if (acl_create_entry(to_acl, &to_entry) != 0) + return -1; + acl_copy_entry(to_entry, from_entry); + acl_set_tag_type(to_entry, to_type); + return 0; + } else { + return 1; + } +} + + +void +print_test( + FILE *file, + const char *path_p, + const struct stat *st, + const acl_t acl, + const acl_t default_acl) +{ + uid_t uid = st->st_uid; + gid_t gid = st->st_gid; + const char *str; + + fprintf(file, "# file: %s\n", path_p); + if (uid != ACL_UNDEFINED_ID) { + if ((str = user_name(uid)) != NULL) + fprintf(file, "# owner: %s\n", str); + else + fprintf(file, "# owner: %d\n", (int)uid); + } + if (gid != ACL_UNDEFINED_ID) { + if ((str = group_name(gid)) != NULL) + fprintf(file, "# group: %s\n", str); + else + fprintf(file, "# group: %d\n", (int)gid); + } + if (acl) { + if (acl_entries(acl) == 0) + fprintf(file, _("# (empty acl)\n")); + else + acl_print(file, acl, NULL, + TEXT_SOME_EFFECTIVE | TEXT_SMART_INDENT); + } else { + fprintf(file, _("# (acl unchanged)\n")); + } + if (default_acl) { + if (acl_entries(default_acl) == 0) { + if (S_ISDIR(st->st_mode)) + fprintf(file, _("# (empty default acl)\n")); + } else { + acl_print(file, default_acl, "default:", + TEXT_SOME_EFFECTIVE | TEXT_SMART_INDENT); + } + } else { + if (S_ISDIR(st->st_mode)) + fprintf(file, _("# (default acl unchanged)\n")); + } + + fprintf(file, "\n"); +} + + +static void +set_perm( + acl_entry_t ent, + mode_t add, + mode_t remove) +{ + acl_permset_t set; + + acl_get_permset(ent, &set); + remove &= ~add; + if (remove & S_IROTH) + acl_delete_perm(set, ACL_READ); + if (remove & S_IWOTH) + acl_delete_perm(set, ACL_WRITE); + if (remove & S_IXOTH) + acl_delete_perm(set, ACL_EXECUTE); + if (add & S_IROTH) + acl_add_perm(set, ACL_READ); + if (add & S_IWOTH) + acl_add_perm(set, ACL_WRITE); + if (add & S_IXOTH) + acl_add_perm(set, ACL_EXECUTE); +} + + +static int +retrieve_acl( + const char *path_p, + acl_type_t type, + const struct stat *st, + acl_t *old_acl, + acl_t *acl) +{ + if (*acl) + return 0; + *acl = NULL; + *old_acl = acl_get_file(path_p, type); + if (*old_acl == NULL && (errno == ENOSYS || errno == ENOTSUP)) { + if (type == ACL_TYPE_ACCESS) + *old_acl = acl_from_mode(st->st_mode); + else + *old_acl = acl_init(0); + } + if (*old_acl == NULL) + return -1; + *acl = acl_dup(*old_acl); + if (*acl == NULL) + return -1; + return 0; +} + + +static int +remove_extended_entries( + acl_t acl) +{ + acl_entry_t ent, group_obj; + acl_permset_t mask_permset, group_obj_permset; + acl_tag_t tag; + int error; + + ent = find_entry(acl, ACL_MASK, ACL_UNDEFINED_ID); + group_obj = find_entry(acl, ACL_GROUP_OBJ, ACL_UNDEFINED_ID); + if (ent && group_obj) { + if (!acl_get_permset(ent, &mask_permset) && + !acl_get_permset(group_obj, &group_obj_permset)) { + if (!acl_get_perm(mask_permset, ACL_READ)) + acl_delete_perm(group_obj_permset, ACL_READ); + if (!acl_get_perm(mask_permset, ACL_WRITE)) + acl_delete_perm(group_obj_permset, ACL_WRITE); + if (!acl_get_perm(mask_permset, ACL_EXECUTE)) + acl_delete_perm(group_obj_permset, ACL_EXECUTE); + } + } + + error = acl_get_entry(acl, ACL_FIRST_ENTRY, &ent); + while (error == 1) { + acl_get_tag_type(ent, &tag); + switch(tag) { + case ACL_USER: + case ACL_GROUP: + case ACL_MASK: + acl_delete_entry(acl, ent); + break; + default: + break; + } + + error = acl_get_entry(acl, ACL_NEXT_ENTRY, &ent); + } + if (error < 0) + return -1; + return 0; +} + + +#define RETRIEVE_ACL(type) ({ \ + error = retrieve_acl(path_p, type, st, old_xacl, xacl); \ + if (error) \ + goto fail; \ + }) + +int +do_set( + const char *path_p, + const struct stat *st, + const seq_t seq) +{ + acl_t old_acl = NULL, old_default_acl = NULL; + acl_t acl = NULL, default_acl = NULL; + acl_t *xacl, *old_xacl; + acl_entry_t ent; + cmd_t cmd; + int which_entry; + int errors = 0, error; + char *acl_text; + int acl_modified = 0, default_acl_modified = 0; + int acl_mask_provided = 0, default_acl_mask_provided = 0; + + /* Execute the commands in seq (read ACLs on demand) */ + error = seq_get_cmd(seq, SEQ_FIRST_CMD, &cmd); + if (error == 0) + return 0; + while (error == 1) { + if (cmd->c_type == ACL_TYPE_ACCESS) { + xacl = &acl; + old_xacl = &old_acl; + acl_modified = 1; + if (cmd->c_tag == ACL_MASK) + acl_mask_provided = 1; + } else { + xacl = &default_acl; + old_xacl = &old_default_acl; + default_acl_modified = 1; + if (cmd->c_tag == ACL_MASK) + default_acl_mask_provided = 1; + } + + switch(cmd->c_cmd) { + case CMD_ENTRY_REPLACE: + RETRIEVE_ACL(cmd->c_type); + ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); + if (!ent) { + if (acl_create_entry(xacl, &ent) != 0) + goto fail; + acl_set_tag_type(ent, cmd->c_tag); + if (cmd->c_id != ACL_UNDEFINED_ID) + acl_set_qualifier( + ent, &cmd->c_id); + } + set_perm(ent, cmd->c_perm, ~cmd->c_perm); + break; + + case CMD_ENTRY_ADD: + RETRIEVE_ACL(cmd->c_type); + ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); + if (ent) + set_perm(ent, cmd->c_perm, 0); + break; + + case CMD_ENTRY_SUBTRACT: + RETRIEVE_ACL(cmd->c_type); + ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); + if (ent) + set_perm(ent, 0, cmd->c_perm); + break; + + case CMD_REMOVE_ENTRY: + RETRIEVE_ACL(cmd->c_type); + ent = find_entry(*xacl, cmd->c_tag, cmd->c_id); + if (ent) + acl_delete_entry(*xacl, ent); + else + /* ignore */; + break; + + case CMD_REMOVE_EXTENDED_ACL: + RETRIEVE_ACL(cmd->c_type); + remove_extended_entries(acl); + break; + + case CMD_REMOVE_ACL: + RETRIEVE_ACL(cmd->c_type); + acl_free(*xacl); + *xacl = acl_init(5); + if (!*xacl) + goto fail; + break; + + default: + errno = EINVAL; + goto fail; + } + + error = seq_get_cmd(seq, SEQ_NEXT_CMD, &cmd); + } + + if (error < 0) + goto fail; + + /* Try to fill in missing entries */ + if (default_acl && acl_entries(default_acl) != 0) { + xacl = &acl; + old_xacl = &old_acl; + + if (!find_entry(default_acl, ACL_USER_OBJ, ACL_UNDEFINED_ID)) { + if (!acl) + RETRIEVE_ACL(ACL_TYPE_ACCESS); + clone_entry(acl, ACL_USER_OBJ, + &default_acl, ACL_USER_OBJ); + } + if (!find_entry(default_acl, ACL_GROUP_OBJ, ACL_UNDEFINED_ID)) { + if (!acl) + RETRIEVE_ACL(ACL_TYPE_ACCESS); + clone_entry(acl, ACL_GROUP_OBJ, + &default_acl, ACL_GROUP_OBJ); + } + if (!find_entry(default_acl, ACL_OTHER, ACL_UNDEFINED_ID)) { + if (!acl) + RETRIEVE_ACL(ACL_TYPE_ACCESS); + clone_entry(acl, ACL_OTHER, + &default_acl, ACL_OTHER); + } + } + + /* update mask entries and check if ACLs are valid */ + if (acl && acl_modified) { + if (acl_equiv_mode(acl, NULL) != 0) { + if (!acl_mask_provided && + !find_entry(acl, ACL_MASK, ACL_UNDEFINED_ID)) + clone_entry(acl, ACL_GROUP_OBJ, + &acl, ACL_MASK); + if (opt_recalculate != -1 && + (!acl_mask_provided || opt_recalculate == 1)) + acl_calc_mask(&acl); + } + + error = acl_check(acl, &which_entry); + if (error < 0) + goto fail; + if (error > 0) { + acl_text = acl_to_any_text( + acl, NULL, NULL, ',', + NULL, TEXT_NO_EFFECTIVE); + fprintf(stderr, _("%s: %s: Resulting ACL `%s': " + "%s at entry %d\n"), progname, path_p, + acl_text, acl_error(error), which_entry+1); + acl_free(acl_text); + errors++; + goto cleanup; + } + } + + if (default_acl && acl_entries(default_acl) != 0 && + default_acl_modified) { + if (acl_equiv_mode(default_acl, NULL) != 0) { + if (!default_acl_mask_provided && + !find_entry(default_acl,ACL_MASK,ACL_UNDEFINED_ID)) + clone_entry(default_acl, ACL_GROUP_OBJ, + &default_acl, ACL_MASK); + if (opt_recalculate != -1 && + (!default_acl_mask_provided || + opt_recalculate == 1)) + acl_calc_mask(&default_acl); + } + + error = acl_check(default_acl, &which_entry); + if (error < 0) + goto fail; + if (error > 0) { + acl_text = acl_to_any_text( + default_acl, NULL, NULL, ',', + NULL, TEXT_NO_EFFECTIVE); + fprintf(stderr, _("%s: %s: Resulting default ACL " + "`%s': %s at entry %d\n"), + progname, path_p, acl_text, + acl_error(error), which_entry+1); + acl_free(acl_text); + errors++; + goto cleanup; + } + } + + /* Only directores can have a default ACL */ + if (default_acl && !S_ISDIR(st->st_mode) && opt_recursive) { + /* In recursive mode, ignore default ACLs for files */ + acl_free(default_acl); + default_acl = NULL; + } + + /* check which ACLs have changed */ + if (acl && old_acl && acl_cmp(old_acl, acl) == 0) { + acl_free(acl); + acl = NULL; + } + if ((default_acl && old_default_acl && + acl_cmp(old_default_acl, default_acl) == 0)) { + acl_free(default_acl); + default_acl = NULL; + } + + /* update the file system */ + if (opt_test) { + print_test(stdout, path_p, st, + acl, default_acl); + goto cleanup; + } + if (acl) { + if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) != 0) { + if (errno != ENOSYS && errno != ENOTSUP) + goto fail; + if (acl_set_file_mode(path_p, ACL_TYPE_ACCESS, + acl) != 0) + goto fail; + } + } + if (default_acl) { + if (S_ISDIR(st->st_mode)) { + if (acl_entries(default_acl) == 0) { + if (acl_delete_def_file(path_p) != 0) + goto fail; + } else { + if (acl_set_file(path_p, ACL_TYPE_DEFAULT, + default_acl) != 0) { + if (errno != ENOSYS && + errno != ENOTSUP) + goto fail; + if (acl_set_file_mode(path_p, + ACL_TYPE_DEFAULT, + default_acl) != 0) + goto fail; + } + } + } else { + if (acl_entries(default_acl) != 0) { + fprintf(stderr, _("%s: %s: Only directories " + "can have a default ACL\n"), + progname, path_p); + errors++; + goto cleanup; + } + } + } + + error = 0; + +cleanup: + if (acl) + acl_free(acl); + if (old_acl) + acl_free(old_acl); + if (default_acl) + acl_free(default_acl); + if (old_default_acl) + acl_free(old_default_acl); + return errors; + +fail: + fprintf(stderr, "%s: %s: %s\n", progname, path_p, strerror(errno)); + errors++; + goto cleanup; +} + diff --git a/setfacl/parse.c b/setfacl/parse.c new file mode 100644 index 0000000..7efd8cc --- /dev/null +++ b/setfacl/parse.c @@ -0,0 +1,550 @@ +/* + File: parse.c + (Linux Access Control List Management) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> +#include <grp.h> +#include "sys/acl.h" + +#include "sequence.h" +#include "parse.h" + +#define SKIP_WS(x) ({ \ + while (*(x)==' ' || *(x)=='\t' || *(x)=='\n' || *(x)=='\r') \ + (x)++; \ + }) + + +static int +skip_tag_name( + const char **text_p, + const char *token) +{ + size_t len = strlen(token); + const char *text = *text_p; + + SKIP_WS(text); + if (strncmp(text, token, len) == 0) { + text += len; + goto delimiter; + } + if (*text == *token) { + text++; + goto delimiter; + } + return 0; + +delimiter: + SKIP_WS(text); + if (*text == ':') { + *text_p = text+1; + return 1; + } + if (*text == ',' || *text == '\0') { + *text_p = text; + return 1; + } + return 0; +} + + +static char * +get_token( + const char **text_p) +{ + char *token = NULL; + const char *ep; + + ep = *text_p; + SKIP_WS(ep); + + while (*ep!='\0' && *ep!='\r' && *ep!='\n' && *ep!=':' && *ep!=',') + ep++; + if (ep == *text_p) + goto after_token; + token = (char*)malloc(ep - *text_p + 1); + if (token == 0) + goto after_token; + memcpy(token, *text_p, (ep - *text_p)); + token[ep - *text_p] = '\0'; +after_token: + if (*ep == ':') + ep++; + *text_p = ep; + return token; +} + + +static int +get_id( + const char *token, + id_t *id_p) +{ + char *ep; + long l; + l = strtol(token, &ep, 0); + if (*ep != '\0') + return -1; + if (l < 0) { + /* + Negative values are interpreted as 16-bit numbers, + so that id -2 maps to 65534 (nobody/nogroup), etc. + */ + l &= 0xFFFF; + } + *id_p = l; + return 0; +} + + +static int +get_uid( + const char *token, + uid_t *uid_p) +{ + struct passwd *passwd; + + if (get_id(token, (id_t *)uid_p) == 0) + goto accept; + passwd = getpwnam(token); + if (passwd) { + *uid_p = passwd->pw_uid; + goto accept; + } + return -1; + +accept: + return 0; +} + + +static int +get_gid( + const char *token, + gid_t *gid_p) +{ + struct group *group; + + if (get_id(token, (id_t *)gid_p) == 0) + goto accept; + group = getgrnam(token); + if (group) { + *gid_p = group->gr_gid; + goto accept; + } + return -1; + +accept: + return 0; +} + + +/* + Parses the next acl entry in text_p. + + Returns: + -1 on error, 0 on success. +*/ + +cmd_t +parse_acl_cmd( + const char **text_p, + int seq_cmd, + int parse_mode) +{ + cmd_t cmd = cmd_init(); + char *str; + const char *backup; + int error, perm_chars; + if (!cmd) + return NULL; + + cmd->c_cmd = seq_cmd; + cmd->c_type = ACL_TYPE_ACCESS; + cmd->c_id = ACL_UNDEFINED_ID; + cmd->c_perm = 0; + + if (parse_mode & SEQ_PARSE_DEFAULT) { + /* check for default acl entry */ + if (skip_tag_name(text_p, "default")) + cmd->c_type = ACL_TYPE_DEFAULT; + } + + /* parse acl entry type */ + switch (**text_p) { + case 'u': /* user */ + skip_tag_name(text_p, "user"); + +user_entry: + backup = *text_p; + str = get_token(text_p); + if (str) { + cmd->c_tag = ACL_USER; + error = get_uid(str, &cmd->c_id); + free(str); + if (error) { + *text_p = backup; + goto fail; + } + } else { + cmd->c_tag = ACL_USER_OBJ; + } + break; + + case 'g': /* group */ + if (!skip_tag_name(text_p, "group")) + goto user_entry; + + backup = *text_p; + str = get_token(text_p); + if (str) { + cmd->c_tag = ACL_GROUP; + error = get_gid(str, &cmd->c_id); + free(str); + if (error) { + *text_p = backup; + goto fail; + } + } else { + cmd->c_tag = ACL_GROUP_OBJ; + } + break; + + case 'o': /* other */ + if (!skip_tag_name(text_p, "other")) + goto user_entry; + /* skip empty entry qualifier field (this field may + be missing for compatibility with Solaris.) */ + SKIP_WS(*text_p); + if (**text_p == ':') + (*text_p)++; + cmd->c_tag = ACL_OTHER; + break; + + case 'm': /* mask */ + if (!skip_tag_name(text_p, "mask")) + goto user_entry; + /* skip empty entry qualifier field (this field may + be missing for compatibility with Solaris.) */ + SKIP_WS(*text_p); + if (**text_p == ':') + (*text_p)++; + cmd->c_tag = ACL_MASK; + break; + + default: /* assume "user:" */ + goto user_entry; + } + + SKIP_WS(*text_p); + if (**text_p == ',' || **text_p == '\0') { + if (parse_mode & SEQ_PARSE_NO_PERM) + return cmd; + else + goto fail; + } + if (!(parse_mode & SEQ_PARSE_WITH_PERM)) + return cmd; + + if (parse_mode & SEQ_PARSE_WITH_RELATIVE) { + if (**text_p == '+') { + (*text_p)++; + cmd->c_cmd = CMD_ENTRY_ADD; + } else if (**text_p == '^') { + (*text_p)++; + cmd->c_cmd = CMD_ENTRY_SUBTRACT; + } else { + if (!(parse_mode & SEQ_PARSE_NO_RELATIVE)) + goto fail; + } + } + + /* parse permissions */ + SKIP_WS(*text_p); + if (**text_p >= '0' && **text_p <= '7') { + cmd->c_perm = 0; + while (**text_p == '0') + (*text_p)++; + if (**text_p >= '1' && **text_p <= '7') { + cmd->c_perm = (*(*text_p)++ - '0'); + } + + return cmd; + } + + for (perm_chars=0; perm_chars<3; perm_chars++, (*text_p)++) { + switch(**text_p) { + case 'r': + if (cmd->c_perm & S_IROTH) + goto fail; + cmd->c_perm |= S_IROTH; + break; + + case 'w': + if (cmd->c_perm & S_IWOTH) + goto fail; + cmd->c_perm |= S_IWOTH; + break; + + case 'x': + if (cmd->c_perm & S_IXOTH) + goto fail; + cmd->c_perm |= S_IXOTH; + break; + + /*case 'X': + if (cmd->c_perm & ...) + goto fail; + cmd->c_perm |= ...; + break:*/ + + case '-': + /* ignore */ + break; + + default: + if (perm_chars == 0) + goto fail; + return cmd; + } + } + if (perm_chars != 3) + goto fail; + return cmd; + +fail: + cmd_free(cmd); + return NULL; +} + + +/* + Parse a comma-separated list of acl entries. + + which is set to the index of the first character that was not parsed, + or -1 in case of success. +*/ +int +parse_acl_seq( + seq_t seq, + const char *text_p, + int *which, + int seq_cmd, + int parse_mode) +{ + const char *initial_text_p = text_p; + cmd_t cmd; + + if (which) + *which = -1; + + while (*text_p != '\0') { + cmd = parse_acl_cmd(&text_p, seq_cmd, parse_mode); + if (cmd == NULL) { + errno = EINVAL; + goto fail; + } + if (seq_append(seq, cmd) != 0) { + cmd_free(cmd); + goto fail; + } + SKIP_WS(text_p); + if (*text_p != ',') + break; + text_p++; + } + + if (*text_p != '\0') { + errno = EINVAL; + goto fail; + } + + return 0; + +fail: + if (which) + *which = (text_p - initial_text_p); + return -1; +} + + + +int +read_acl_comments( + FILE *file, + int *line, + char **path_p, + uid_t *uid_p, + gid_t *gid_p) +{ + int c; + char linebuf[1024]; + const char *cp; + char *p; + int comments_read = 0; + + if (path_p) + *path_p = NULL; + if (uid_p) + *uid_p = ACL_UNDEFINED_ID; + if (gid_p) + *gid_p = ACL_UNDEFINED_ID; + + for(;;) { + c = fgetc(file); + if (c == EOF) + break; + if (c==' ' || c=='\t' || c=='\r' || c=='\n') { + if (c=='\n') + (*line)++; + continue; + } + if (c != '#') { + ungetc(c, file); + break; + } + if (line) + (*line)++; + + if (fgets(linebuf, sizeof(linebuf), file) == NULL) + break; + + comments_read = 1; + + p = strrchr(linebuf, '\0'); + while (p > linebuf && + (*(p-1)=='\r' || *(p-1)=='\n')) { + p--; + *p = '\0'; + } + + cp = linebuf; + SKIP_WS(cp); + if (strncmp(cp, "file:", 5) == 0) { + cp += 5; + SKIP_WS(cp); + + if (path_p) { + if (*path_p) + goto fail; + *path_p = (char*)malloc(strlen(cp)+1); + if (!*path_p) + return -1; + strcpy(*path_p, cp); + } + } else if (strncmp(cp, "owner:", 6) == 0) { + cp += 6; + SKIP_WS(cp); + + if (uid_p) { + if (*uid_p != ACL_UNDEFINED_ID) + goto fail; + if (get_uid(cp, uid_p) != 0) + continue; + } + } else if (strncmp(cp, "group:", 6) == 0) { + cp += 6; + SKIP_WS(cp); + + if (gid_p) { + if (*gid_p != ACL_UNDEFINED_ID) + goto fail; + if (get_gid(cp, gid_p) != 0) + continue; + } + } + } + if (ferror(file)) + return -1; + return comments_read; +fail: + if (path_p && *path_p) + free(*path_p); + return -1; +} + + +int +read_acl_seq( + FILE *file, + seq_t seq, + int seq_cmd, + int parse_mode, + int *line, + int *which) +{ + char linebuf[1024]; + const char *cp; + cmd_t cmd; + + if (which) + *which = -1; + + for(;;) { + if (fgets(linebuf, sizeof(linebuf), file) == NULL) + break; + if (line) + (*line)++; + + cp = linebuf; + SKIP_WS(cp); + if (*cp == '\0') { + if (!(parse_mode & SEQ_PARSE_MULTI)) + continue; + break; + } else if (*cp == '#') { + continue; + } + + cmd = parse_acl_cmd(&cp, seq_cmd, parse_mode); + if (cmd == NULL) { + errno = EINVAL; + goto fail; + } + if (seq_append(seq, cmd) != 0) { + cmd_free(cmd); + goto fail; + } + + SKIP_WS(cp); + if (*cp != '\0' && *cp != '#') { + errno = EINVAL; + goto fail; + } + } + + if (ferror(file)) + goto fail; + return 0; + +fail: + if (which) + *which = (cp - linebuf); + return -1; +} + diff --git a/setfacl/parse.h b/setfacl/parse.h new file mode 100644 index 0000000..6aa2685 --- /dev/null +++ b/setfacl/parse.h @@ -0,0 +1,86 @@ +/* + File: parse.h + (Linux Access Control List Management) + + Copyright (C) 1999 by Andreas Gruenbacher + <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __PARSE_H +#define __PARSE_H + + +#include <stdlib.h> +#include <sys/types.h> +#include "sequence.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* parse options */ + +#define SEQ_PARSE_WITH_PERM (0x0001) +#define SEQ_PARSE_NO_PERM (0x0002) +#define SEQ_PARSE_ANY_PERM (0x0001|0x0002) + +#define SEQ_PARSE_WITH_RELATIVE (0x0004) +#define SEQ_PARSE_NO_RELATIVE (0x0008) +#define SEQ_PARSE_ANY_RELATIVE (0x0004|0x0008) + +#define SEQ_PARSE_MULTI (0x0010) +#define SEQ_PARSE_DEFAULT (0x0020) /* "default:" = default acl */ + + +cmd_t +parse_acl_cmd( + const char **text_p, + int seq_cmd, + int parse_mode); +int +parse_acl_seq( + seq_t seq, + const char *text_p, + int *which, + int seq_cmd, + int parse_mode); +int +read_acl_comments( + FILE *file, + int *line, + char **path_p, + uid_t *uid_p, + gid_t *gid_p); +int +read_acl_seq( + FILE *file, + seq_t seq, + int seq_cmd, + int parse_mode, + int *line, + int *which); + + +#ifdef __cplusplus +} +#endif + + +#endif /* __PARSE_H */ + diff --git a/setfacl/sequence.c b/setfacl/sequence.c new file mode 100644 index 0000000..091644d --- /dev/null +++ b/setfacl/sequence.c @@ -0,0 +1,162 @@ +/* + File: sequence.c + (Linux Access Control List Management) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include <stdlib.h> +#include "sequence.h" + + +cmd_t +cmd_init( + void) +{ + return (cmd_t)malloc(sizeof(struct cmd_obj)); +} + + +void +cmd_free( + cmd_t cmd) +{ + free(cmd); +} + + +seq_t +seq_init( + void) +{ + seq_t seq = (seq_t)malloc(sizeof(struct seq_obj)); + if (seq == NULL) + return NULL; + seq->s_first = seq->s_last = NULL; + return seq; +} + + +int +seq_free( + seq_t seq) +{ + cmd_t cmd = seq->s_first; + while (cmd) { + seq->s_first = seq->s_first->c_next; + cmd_free(cmd); + cmd = seq->s_first; + } + free(seq); + return 0; +} + + +int +seq_empty( + seq_t seq) +{ + return (seq->s_first == NULL); +} + + +int +seq_append( + seq_t seq, + cmd_t cmd) +{ + cmd->c_next = NULL; + if (seq->s_first == NULL) { + seq->s_first = seq->s_last = cmd; + } else { + seq->s_last->c_next = cmd; + seq->s_last = cmd; + } + return 0; +} + + +int +seq_append_cmd( + seq_t seq, + cmd_tag_t cmd, + acl_type_t type) +{ + cmd_t cmd_d = cmd_init(); + if (cmd_d == NULL) + return -1; + cmd_d->c_cmd = cmd; + cmd_d->c_type = type; + if (seq_append(seq, cmd_d) != 0) { + cmd_free(cmd_d); + return -1; + } + return 0; +} + + +int +seq_get_cmd( + seq_t seq, + int which, + cmd_t *cmd) +{ + if (which == SEQ_FIRST_CMD) { + if (seq->s_first == NULL) + return 0; + if (cmd) + *cmd = seq->s_first; + return 1; + } else if (which == SEQ_NEXT_CMD) { + if (cmd == NULL) + return -1; + if (*cmd) { + *cmd = (*cmd)->c_next; + return (*cmd == NULL) ? 0 : 1; + } + return 0; + } else { + return -1; + } +} + + +int +seq_delete_cmd( + seq_t seq, + cmd_t cmd) +{ + cmd_t prev = seq->s_first; + + if (cmd == seq->s_first) { + seq->s_first = seq->s_first->c_next; + cmd_free(cmd); + return 0; + } + while (prev != NULL && prev->c_next != cmd) + prev = prev->c_next; + if (prev == NULL) + return -1; + if (cmd == seq->s_last) + seq->s_last = prev; + prev->c_next = NULL; + cmd_free(cmd); + return 0; +} + diff --git a/setfacl/sequence.h b/setfacl/sequence.h new file mode 100644 index 0000000..12862f4 --- /dev/null +++ b/setfacl/sequence.h @@ -0,0 +1,111 @@ +/* + File: sequence.h + (Linux Access Control List Management) + + Copyright (C) 1999 by Andreas Gruenbacher + <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef __SEQUENCE_H +#define __SEQUENCE_H + + +#include <sys/acl.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef unsigned int cmd_tag_t; + +struct cmd_obj { + cmd_tag_t c_cmd; + acl_type_t c_type; + acl_tag_t c_tag; + uid_t c_id; + mode_t c_perm; + struct cmd_obj *c_next; +}; + +typedef struct cmd_obj *cmd_t; + +struct seq_obj { + cmd_t s_first; + cmd_t s_last; +}; + +typedef struct seq_obj *seq_t; + +/* command types */ +#define CMD_ENTRY_REPLACE (0) +#define CMD_ENTRY_ADD (1) +#define CMD_ENTRY_SUBTRACT (2) +#define CMD_REMOVE_ENTRY (3) +#define CMD_REMOVE_EXTENDED_ACL (4) +#define CMD_REMOVE_ACL (5) + +#define SEQ_FIRST_CMD (0) +#define SEQ_NEXT_CMD (1) + + +/* command sequence manipulation */ + +cmd_t +cmd_init( + void); +void +cmd_free( + cmd_t cmd); +seq_t +seq_init( + void); +int +seq_free( + seq_t seq); +int +seq_empty( + seq_t seq); +int +seq_append( + seq_t seq, + cmd_t cmd); +int +seq_append_cmd( + seq_t seq, + cmd_tag_t cmd, + acl_type_t type); +int +seq_get_cmd( + seq_t seq, + int which, + cmd_t *cmd); +int +seq_delete_cmd( + seq_t seq, + cmd_t cmd); + + +#ifdef __cplusplus +} +#endif + + +#endif /* __SEQUENCE_H */ + diff --git a/setfacl/setfacl.c b/setfacl/setfacl.c new file mode 100644 index 0000000..b7c89a5 --- /dev/null +++ b/setfacl/setfacl.c @@ -0,0 +1,687 @@ +/* + File: setfacl.c + (Linux Access Control List Management) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> +#include <dirent.h> +#include <ftw.h> +#include "sequence.h" +#include "parse.h" + +//#define _GNU_SOURCE +#include <getopt.h> + +#include <locale.h> +#include <libintl.h> +#define _(String) gettext (String) + +extern int +do_set( + const char *path_p, + const struct stat *stat_p, + const seq_t seq); + + +#define POSIXLY_CORRECT_STR "POSIXLY_CORRECT" + +/* '-' stands for `process non-option arguments in loop' */ +#if !POSIXLY_CORRECT +# define CMD_LINE_OPTIONS "-:bkndm:M:x:X:vh" "s:S:RLP" +# define CMD_LINE_SPEC "[-bkndRLPvh] " \ + "{ -s|-S|-m|-M|-x|-X ... } file ..." +#endif +#define POSIXLY_CMD_LINE_OPTIONS "-:bkndm:M:x:X:vh" +#define POSIXLY_CMD_LINE_SPEC "[-bkndvh] {-m|-M|-x|-X ... } file ..." + +struct option long_options[] = { +#if !POSIXLY_CORRECT + { "set", 0, 0, 's' }, + { "set-file", 0, 0, 'S' }, + + { "mask", 0, 0, 'r' }, + { "recursive", 0, 0, 'R' }, + { "logical", 0, 0, 'L' }, + { "physical", 0, 0, 'P' }, + { "restore", 1, 0, 'B' }, + { "test", 0, 0, 't' }, +#endif + { "modify", 0, 0, 'm' }, + { "modify-file", 0, 0, 'M' }, + { "remove", 0, 0, 'x' }, + { "remove-file", 0, 0, 'X' }, + + { "default", 0, 0, 'd' }, + { "no-mask", 0, 0, 'n' }, + { "remove-all", 0, 0, 'b' }, + { "remove-default", 0, 0, 'k' }, + { "version", 0, 0, 'v' }, + { "help", 0, 0, 'h' }, + { NULL, 0, 0, 0 }, +}; + +const char *progname; +const char *cmd_line_options, *cmd_line_spec; + +int opt_recursive; /* recurse into sub-directories? */ +int opt_walk_logical; /* always follow symbolic links */ +int opt_walk_physical; /* never follow symbolic links */ +int opt_recalculate; /* recalculate mask entry (0=default, 1=yes, -1=no) */ +int opt_promote; /* promote access ACL to default ACL */ +int opt_test; /* do not write to the file system. + Print what would happen instead. */ +#if POSIXLY_CORRECT +const int posixly_correct = 1; /* Posix compatible behavior! */ +#else +int posixly_correct; /* Posix compatible behavior? */ +#endif +int chown_error; +int promote_warning; + + +int +promote( + seq_t seq) +{ + cmd_t cmd; + int error; + +restart: + error = seq_get_cmd(seq, SEQ_FIRST_CMD, &cmd); + while (error == 1) { + if (cmd->c_type == ACL_TYPE_DEFAULT) { + error = seq_delete_cmd(seq, cmd); + if (error != 0) + return -1; + goto restart; + } + + error = seq_get_cmd(seq, SEQ_NEXT_CMD, &cmd); + } + + error = seq_get_cmd(seq, SEQ_FIRST_CMD, &cmd); + while (error == 1) { + cmd->c_type = ACL_TYPE_DEFAULT; + error = seq_get_cmd(seq, SEQ_NEXT_CMD, &cmd); + } + return 0; +} + + +#if !POSIXLY_CORRECT +int +restore( + FILE *file, + const char *filename) +{ + char *path_p; + struct stat stat; + uid_t uid; + gid_t gid; + seq_t seq = NULL; + int line = 0, backup_line; + int error, status = 0; + + memset(&stat, 0, sizeof(stat)); + + for(;;) { + backup_line = line; + error = read_acl_comments(file, &line, &path_p, &uid, &gid); + if (error < 0) + goto fail; + if (error == 0) + return 0; + + if (path_p == NULL) { + if (filename) { + fprintf(stderr, _("%s: %s: No filename found " + "in line %d, aborting\n"), + progname, filename, backup_line); + } else { + fprintf(stderr, _("%s: No filename found in " + "line %d of standard input, " + "aborting\n"), + progname, backup_line); + } + goto getout; + } + + if (!(seq = seq_init())) + goto fail; + if (seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_ACCESS) || + seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_DEFAULT)) + goto fail; + + error = read_acl_seq(file, seq, CMD_ENTRY_REPLACE, + SEQ_PARSE_WITH_PERM | + SEQ_PARSE_NO_RELATIVE | + SEQ_PARSE_DEFAULT | + SEQ_PARSE_MULTI, + &line, NULL); + if (error != 0) { + fprintf(stderr, _("%s: %s: %s in line %d\n"), + progname, filename, strerror(errno), line); + goto getout; + } + + error = lstat(path_p, &stat); + if (opt_test && error != 0) { + fprintf(stderr, "%s: %s: %s\n", progname, path_p, + strerror(errno)); + status = 1; + } + stat.st_uid = uid; + stat.st_gid = gid; + + error = do_set(path_p, &stat, seq); + if (error != 0) { + status = 1; + goto resume; + } + + if (!opt_test && + (uid != ACL_UNDEFINED_ID || gid != ACL_UNDEFINED_ID)) { + if (chown(path_p, uid, gid) != 0) { + fprintf(stderr, _("%s: %s: Cannot change " + "owner/group: %s\n"), + progname, path_p, strerror(errno)); + status = 1; + } + } +resume: + if (path_p) { + free(path_p); + path_p = NULL; + } + if (seq) { + seq_free(seq); + seq = NULL; + } + } + +getout: + if (path_p) { + free(path_p); + path_p = NULL; + } + if (seq) { + seq_free(seq); + seq = NULL; + } + return status; + +fail: + fprintf(stderr, "%s: %s: %s\n", progname, filename, strerror(errno)); + status = 1; + goto getout; +} +#endif + + +void help(void) +{ + printf(_("%s %s -- set file access control lists\n"), + progname, VERSION); + printf(_("Usage: %s %s\n"), + progname, cmd_line_spec); +#if !POSIXLY_CORRECT + if (!posixly_correct) { + printf(_( +" -s, --set=acl set the ACL of file(s), replacing the current ACL\n" +" -S, --set-file=file read ACL entries to set from file\n")); + } +#endif + printf(_( +" -m, --modify=acl modify the current ACL(s) of file(s)\n" +" -M, --modify-file=file read ACL entries to modify from file\n" +" -x, --remove=acl remove entries from the ACL(s) of file(s)\n" +" -X, --remove-file=file read ACL entries to remove from file\n" +" -b, --remove-all remove all extended ACL entries\n" +" -k, --remove-default remove the default ACL\n")); +#if !POSIXLY_CORRECT + if (!posixly_correct) { + printf(_( +" --mask do recalculate the effective rights mask\n")); + } +#endif + printf(_( +" -n, --no-mask don't recalculate the effective rights mask\n" +" -d, --default operations apply to the default ACL\n")); +#if !POSIXLY_CORRECT + if (!posixly_correct) { + printf(_( +" -R, --recursive recurse into subdirectories\n" +" -L, --logical logical walk, follow symbolic links\n" +" -P, --physical physical walk, do not follow symbolic links\n" +" --restore=file restore ACLs (inverse of `getfacl -R')\n" +" --test test mode (ACLs are not modified)\n")); + } +#endif + printf(_( +" -v, --version print version and exit\n" +" -h, --help this help text\n")); +} + + +char *next_line(FILE *file) +{ + static char line[_POSIX_PATH_MAX], *c; + if (!fgets(line, sizeof(line), file)) + return NULL; + + c = strrchr(line, '\0'); + while (c > line && (*(c-1) == '\n' || + *(c-1) == '\r')) { + c--; + *c = '\0'; + } + return line; +} + + + +static int __errors; +static seq_t __seq; +int __do_set(const char *file, const struct stat *stat, + int flag, struct FTW *ftw) +{ + /* Process the target of a symbolic link, and traverse the link, + only if doing a logical walk, or if the symbolic link was + specified on the command line. Always skip symbolic links if + doing a physical walk. */ + + if (S_ISLNK(stat->st_mode) && + (opt_walk_physical || (ftw->level > 0 && !opt_walk_logical))) + return 0; + + if (do_set(file, stat, __seq)) + __errors++; + return 0; +} + +int walk_tree(const char *file, seq_t seq) +{ + if (!opt_recursive) { + struct stat st; + + if (stat(file, &st)) { + fprintf(stderr, "%s: %s: %s\n", progname, file, + strerror(errno)); + return 1; + } + if (do_set(file, &st, seq)) + return 1; + return 0; + } + + __errors = 0; + __seq = seq; + if (nftw(file, __do_set, 0, opt_recursive * FTW_PHYS)) { + fprintf(stderr, "%s: %s\n", progname, strerror(errno)); + __errors++; + } + return 1; + return __errors; +} + +int next_file(const char *arg, seq_t seq) +{ + char *line; + int errors = 0; + + if (strcmp(arg, "-") == 0) { + while ((line = next_line(stdin))) + errors = walk_tree(line, seq); + } else { + errors = walk_tree(arg, seq); + } + return errors ? 1 : 0; +} + + +#define ERRNO_ERROR(s) \ + ({status = (s); goto errno_error; }) + + +int main(int argc, char *argv[]) +{ + int opt; + int saw_files = 0; + int status = 0; + FILE *file; + int which; + int lineno; + int error; + seq_t seq = NULL; + int seq_cmd, parse_mode; + + progname = argv[0]; + +#if POSIXLY_CORRECT + cmd_line_options = POSIXLY_CMD_LINE_OPTIONS; + cmd_line_spec = _(POSIXLY_CMD_LINE_SPEC); +#else + if (getenv(POSIXLY_CORRECT_STR)) + posixly_correct = 1; + if (!posixly_correct) { + cmd_line_options = CMD_LINE_OPTIONS; + cmd_line_spec = _(CMD_LINE_SPEC); + } else { + cmd_line_options = POSIXLY_CMD_LINE_OPTIONS; + cmd_line_spec = _(POSIXLY_CMD_LINE_SPEC); + } +#endif + + setlocale(LC_MESSAGES, ""); + bindtextdomain(PKG_NAME, LOCALEDIR); + textdomain(PKG_NAME); + + while ((opt = getopt_long(argc, argv, cmd_line_options, + long_options, NULL)) != -1) { + if (opt != '\1' && saw_files) { + if (seq) { + seq_free(seq); + seq = NULL; + } + saw_files = 0; + } + if (seq == NULL) { + if (!(seq = seq_init())) + ERRNO_ERROR(1); + } + + switch (opt) { + case 'b': /* remove all extended entries */ + if (seq_append_cmd(seq, CMD_REMOVE_EXTENDED_ACL, + ACL_TYPE_ACCESS) || + seq_append_cmd(seq, CMD_REMOVE_ACL, + ACL_TYPE_DEFAULT)) + ERRNO_ERROR(1); + break; + + case 'k': /* remove default ACL */ + if (seq_append_cmd(seq, CMD_REMOVE_ACL, + ACL_TYPE_DEFAULT)) + ERRNO_ERROR(1); + break; + + case 'n': /* do not recalculate mask */ + opt_recalculate = -1; + break; + + case 'r': /* force recalculate mask */ + opt_recalculate = 1; + break; + + case 'd': /* operations apply to default ACL */ + opt_promote = 1; + break; + + case 's': /* set */ + if (seq_append_cmd(seq, CMD_REMOVE_ACL, + ACL_TYPE_ACCESS) || + seq_append_cmd(seq, CMD_REMOVE_ACL, + ACL_TYPE_DEFAULT)) + ERRNO_ERROR(1); + seq_cmd = CMD_ENTRY_REPLACE; + parse_mode = SEQ_PARSE_WITH_PERM | + SEQ_PARSE_NO_RELATIVE; + goto set_modify_delete; + + case 'm': /* modify */ + seq_cmd = CMD_ENTRY_REPLACE; + parse_mode = SEQ_PARSE_WITH_PERM; +#if POSIXLY_CORRECT || 1 + parse_mode |= SEQ_PARSE_NO_RELATIVE; +#else + if (posixly_correct) + parse_mode |= SEQ_PARSE_NO_RELATIVE; + else + parse_mode |= SEQ_PARSE_ANY_RELATIVE; +#endif + goto set_modify_delete; + + case 'x': /* delete */ + seq_cmd = CMD_REMOVE_ENTRY; + parse_mode = SEQ_PARSE_NO_RELATIVE; +#if POSIXLY_CORRECT + parse_mode |= SEQ_PARSE_ANY_PERM; +#else + if (posixly_correct) + parse_mode |= SEQ_PARSE_ANY_PERM; + else + parse_mode |= SEQ_PARSE_NO_PERM; +#endif + goto set_modify_delete; + + set_modify_delete: + if (!posixly_correct) + parse_mode |= SEQ_PARSE_DEFAULT; + if (parse_acl_seq(seq, optarg, &which, + seq_cmd, parse_mode) != 0) { + if (which < 0 || + (size_t) which >= strlen(optarg)) { + fprintf(stderr, _("%s: Option " + "-%c incomplete\n"), + progname, opt); + } else { + fprintf(stderr, _("%s: Option " + "-%c: %s near " + "character %d\n"), + progname, opt, + strerror(errno), + which+1); + } + status = 2; + goto cleanup; + } + break; + + case 'S': /* set from file */ + if (seq_append_cmd(seq, CMD_REMOVE_ACL, + ACL_TYPE_ACCESS) || + seq_append_cmd(seq, CMD_REMOVE_ACL, + ACL_TYPE_DEFAULT)) + ERRNO_ERROR(1); + seq_cmd = CMD_ENTRY_REPLACE; + parse_mode = SEQ_PARSE_WITH_PERM | + SEQ_PARSE_NO_RELATIVE; + goto set_modify_delete_from_file; + + case 'M': /* modify from file */ + seq_cmd = CMD_ENTRY_REPLACE; + parse_mode = SEQ_PARSE_WITH_PERM; +#if POSIXLY_CORRECT || 1 + parse_mode |= SEQ_PARSE_NO_RELATIVE; +#else + if (posixly_correct) + parse_mode |= SEQ_PARSE_NO_RELATIVE; + else + parse_mode |= SEQ_PARSE_ANY_RELATIVE; +#endif + goto set_modify_delete_from_file; + + case 'X': /* delete from file */ + seq_cmd = CMD_REMOVE_ENTRY; + parse_mode = SEQ_PARSE_NO_RELATIVE; +#if POSIXLY_CORRECT + parse_mode |= SEQ_PARSE_ANY_PERM; +#else + if (posixly_correct) + parse_mode |= SEQ_PARSE_ANY_PERM; + else + parse_mode |= SEQ_PARSE_NO_PERM; +#endif + goto set_modify_delete_from_file; + + set_modify_delete_from_file: + if (!posixly_correct) + parse_mode |= SEQ_PARSE_DEFAULT; + if (strcmp(optarg, "-") == 0) { + file = stdin; + } else { + file = fopen(optarg, "r"); + if (file == NULL) { + fprintf(stderr, "%s: %s: %s\n", + progname, optarg, + strerror(errno)); + status = 2; + goto cleanup; + } + } + + lineno = 0; + error = read_acl_seq(file, seq, seq_cmd, + parse_mode, &lineno, NULL); + + if (file != stdin) { + fclose(file); + } + + if (error) { + if (!errno) + errno = EINVAL; + + if (file != stdin) { + fprintf(stderr, _("%s: %s in " + "line %d of file %s\n"), + progname, + strerror(errno), + lineno, + optarg); + } else { + fprintf(stderr, _("%s: %s in " + "line %d of standard " + "input\n"), progname, + strerror(errno), + lineno); + } + status = 2; + goto cleanup; + } + break; + + + case '\1': /* file argument */ + if (seq_empty(seq)) + goto synopsis; + if (!saw_files && opt_promote) + promote(seq); + saw_files = 1; + + status = next_file(optarg, seq); + break; + + case 'B': /* restore ACL backup */ + saw_files = 1; + + if (strcmp(optarg, "-") == 0) + file = stdin; + else { + file = fopen(optarg, "r"); + if (file == NULL) { + fprintf(stderr, "%s: %s: %s\n", + progname, optarg, + strerror(errno)); + status = 2; + goto cleanup; + } + } + + status = restore(file, + (file == stdin) ? NULL : optarg); + + if (file != stdin) + fclose(file); + if (status != 0) + goto cleanup; + break; + + case 'R': /* recursive */ + opt_recursive = 1; + break; + + case 'L': /* follow symlinks */ + opt_walk_logical = 1; + opt_walk_physical = 0; + break; + + case 'P': /* do not follow symlinks */ + opt_walk_logical = 0; + opt_walk_physical = 1; + break; + + case 't': /* test mode */ + opt_test = 1; + break; + + case 'v': /* print version and exit */ + printf("%s " VERSION "\n", progname); + status = 0; + goto cleanup; + + case 'h': /* help! */ + help(); + status = 0; + goto cleanup; + + case ':': /* option missing */ + case '?': /* unknown option */ + default: + goto synopsis; + } + } + while (optind < argc) { + if (seq_empty(seq)) + goto synopsis; + if (!saw_files && opt_promote) + promote(seq); + saw_files = 1; + + status = next_file(argv[optind++], seq); + } + if (!saw_files) + goto synopsis; + + goto cleanup; + +synopsis: + fprintf(stderr, _("Usage: %s %s\n"), + progname, cmd_line_spec); + fprintf(stderr, _("Try `%s -h' for more information.\n"), + progname); + status = 2; + goto cleanup; + +errno_error: + fprintf(stderr, "%s: %s\n", progname, strerror(errno)); + goto cleanup; + +cleanup: + if (seq) + seq_free(seq); + return status; +} + diff --git a/setfacl/user_group.c b/setfacl/user_group.c new file mode 100644 index 0000000..11f6867 --- /dev/null +++ b/setfacl/user_group.c @@ -0,0 +1,51 @@ +/* + File: user_group.c + (Linux Access Control List Management) + + Copyright (C) 1999, 2000 + Andreas Gruenbacher, <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <stdlib.h> +#include "user_group.h" + + +const char * +user_name( + uid_t uid) +{ + struct passwd *passwd = getpwuid(uid); + + if (passwd != NULL) + return passwd->pw_name; + else + return NULL; +} + + +const char * +group_name( + gid_t gid) +{ + struct group *group = getgrgid(gid); + + if (group != NULL) + return group->gr_name; + else + return NULL; +} + diff --git a/setfacl/user_group.h b/setfacl/user_group.h new file mode 100644 index 0000000..8be04e6 --- /dev/null +++ b/setfacl/user_group.h @@ -0,0 +1,33 @@ +/* + File: user_group.h + (Linux Access Control List Management) + + Copyright (C) 1999 by Andreas Gruenbacher + <a.gruenbacher@computer.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> + +const char * +user_name( + uid_t uid); +const char * +group_name( + gid_t uid); + diff --git a/test/acl.ea b/test/acl.ea new file mode 100644 index 0000000..6416f65 --- /dev/null +++ b/test/acl.ea @@ -0,0 +1 @@ +system.posix_acl_access=0x010000000100060002000600010000000400040008000600010000001000060020000400 diff --git a/test/block b/test/block new file mode 100644 index 0000000..21d6c12 --- /dev/null +++ b/test/block @@ -0,0 +1,5 @@ +#!/bin/sh + +dd if=/dev/hda8 bs=1024 skip=$1 count=1 2>/dev/null | +hex + diff --git a/test/lib/byteorder.c b/test/lib/byteorder.c new file mode 100644 index 0000000..871ca21 --- /dev/null +++ b/test/lib/byteorder.c @@ -0,0 +1,25 @@ +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 +#define WORDS_BIGENDIAN +#include "byteorder.h" + +__u16 swap16(__u16 u16) { + return cpu_to_le16(u16); +} + +__u32 swap32(__u32 u32) { + return cpu_to_le32(u32); +} + +int main(void) +{ + __u16 u16 = 0xFADE; + __u32 u32 = 0xDEADBEEF; + + printf("0x%X 0x%X\n", u16, u32); + u16 = swap16(u16); + u32 = swap32(u32); + printf("0x%X 0x%X\n", u16, u32); +} + diff --git a/test/lib/check.h b/test/lib/check.h new file mode 100644 index 0000000..ef763bc --- /dev/null +++ b/test/lib/check.h @@ -0,0 +1,21 @@ +#include <errno.h> +#include <string.h> + +#define OK "\033[32mok\033[m" +#define ERROR "\033[31m\033[1mfailed\033[m" +/* integer result */ +#define I(e, x) \ + ({ res = ((x)==0); \ + fprintf(stderr, "[%d] " ## #x ## " : %s -- %s\n", \ + __LINE__, \ + res ? "" : strerror(errno), \ + (res == e) ? OK : ERROR \ + ); }) +/* pointer result */ +#define P(e, x) \ + ({ res = ((x) != NULL); \ + fprintf(stderr, "[%d] " ## #x ## " : %s -- %s\n", \ + __LINE__, \ + res ? "" : strerror(errno), \ + (res == e) ? OK : ERROR \ + ); }) diff --git a/test/lib/mem.c b/test/lib/mem.c new file mode 100644 index 0000000..b478b9f --- /dev/null +++ b/test/lib/mem.c @@ -0,0 +1,50 @@ +/* Tests ACL library memory allocation */ + +#include <stdio.h> +#include <sys/acl.h> + +#include "check.h" + +int main(void) +{ + acl_entry_t entry1, entry2; + void *id_p; + acl_permset_t permset; + acl_t acl; + void *v_p = NULL; + void **v_pp = &v_p; + char *text; + + /* used by macros*/ + int res; + + /* parameter 1 = succeeds */ + P( 1, acl = acl_from_text("user::rw-, group::r--, other:-") ); + P( 1, text = acl_to_text(acl, NULL) ); + I( 1, acl_free(text) ); + I( 0, acl_free(text) ); + P( 1, acl = acl_init(0) ); + I( 1, acl_create_entry(&acl, &entry1) ); + I( 0, acl_create_entry(NULL, &entry1) ); + I( 0, acl_create_entry(v_p, &entry1) ); + I( 0, acl_create_entry((void*)&v_p, &entry1) ); + I( 0, acl_create_entry(&acl, NULL) ); + I( 0, acl_copy_entry(entry1, entry2) ); + I( 0, acl_copy_entry(entry1, v_p) ); + I( 0, acl_free(entry1) ); + I( 1, acl_create_entry(&acl, &entry2) ); + I( 1, acl_copy_entry(entry2, entry1) ); + P( 0, id_p = acl_get_qualifier(entry2) ); + I( 1, acl_set_tag_type(entry2, ACL_USER) ); + P( 1, id_p = acl_get_qualifier(entry2) ); + I( 1, acl_get_permset(entry2, &permset) ); + I( 0, acl_free(permset) ); + I( 1, acl_free(id_p) ); + I( 0, acl_free(id_p) ); + I( 1, acl_free(acl) ); + I( 0, acl_free(acl) ); + I( 0, acl_free(v_pp) ); + + return 0; +} + diff --git a/test/lib/mem.expect b/test/lib/mem.expect new file mode 100644 index 0000000..773fc87 --- /dev/null +++ b/test/lib/mem.expect @@ -0,0 +1,25 @@ +ok 35 acl = acl_from_text("user::rw-, group::r--, other:-") : +ok 36 text = acl_to_text(acl, NULL) : +ok 37 acl_free(text) : +ok 38 acl_free(text) : Invalid argument +ok 39 acl = acl_init(0) : +ok 40 acl_create_entry(&acl, &entry1) : +ok 41 acl_create_entry(NULL, &entry1) : Invalid argument +ok 42 acl_create_entry(v_p, &entry1) : Invalid argument +ok 43 acl_create_entry((void*)&v_p, &entry1) : Invalid argument +ok 44 acl_create_entry(&acl, NULL) : Invalid argument +ok 45 acl_copy_entry(entry1, entry2) : Invalid argument +ok 46 acl_copy_entry(entry1, v_p) : Invalid argument +ok 47 acl_free(entry1) : Invalid argument +ok 48 acl_create_entry(&acl, &entry2) : +ok 49 acl_copy_entry(entry2, entry1) : +ok 50 id_p = acl_get_qualifier(entry2) : Invalid argument +ok 51 acl_set_tag_type(entry2, ACL_USER) : +ok 52 id_p = acl_get_qualifier(entry2) : +ok 53 acl_get_permset(entry2, &permset) : +ok 54 acl_free(permset) : Invalid argument +ok 55 acl_free(id_p) : +ok 56 acl_free(id_p) : Invalid argument +ok 57 acl_free(acl) : +ok 58 acl_free(acl) : Invalid argument +ok 59 acl_free(v_pp) : Invalid argument diff --git a/test/lib/text.c b/test/lib/text.c new file mode 100644 index 0000000..a71bc4a --- /dev/null +++ b/test/lib/text.c @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <sys/acl.h> +#include <string.h> + +#include "check.h" + +int main(void) +{ + acl_t acl; + char *text; + int res; + + P(1, acl = acl_from_text("user::rwx") ); + P(1, text = acl_to_text(acl, NULL) ); + I(1, strcmp(text, "user::rwx") ); + I(1, acl_free(text) ); + P(1, acl = acl_from_text("user::rwx,g::rw") ); + P(1, text = acl_to_text(acl, NULL) ); + I(1, strcmp(text, "user::rwx\ngroup::rw-") ); + I(1, acl_free(text) ); + + return 0; +} + diff --git a/test/perf/TESTS b/test/perf/TESTS new file mode 100644 index 0000000..2401928 --- /dev/null +++ b/test/perf/TESTS @@ -0,0 +1,11 @@ +* Overhead a default ACL causes for creating files +* Overhead ACLs cause for permission checking (deep tree) + - User = owner + - User != owner +* Speed of chmod (e.g., for whole tree) +* Speed of getfacl/setfacl + - Simply get many different ACLs + - Create new ACLs + - Change ACLs of many files +* Speed of ls -l + diff --git a/test/perf/make-tree b/test/perf/make-tree new file mode 100644 index 0000000..472c1cd --- /dev/null +++ b/test/perf/make-tree @@ -0,0 +1,45 @@ +#!/bin/sh + +LEVELS=3 ; [ -z "$1" ] || LEVELS=$1 +DIRS=10 ; [ -z "$2" ] || DIRS=$2 +FILES=10 ; [ -z "$2" ] || FILES=$3 +NUMBER_OF_ACLS=50 ; [ -z "$3" ] || NUMBER_OF_ACLS=$4 + +function random_dir() { + mkdir -p $1 + #setfacl -s "u::rwx,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rwx,g::rx,o:-" $1 +} + +function random_file() { + touch $1 + #setfacl -s "u::rw,u:$[($RANDOM % $NUMBER_OF_ACLS)+1000]:rw,g::r,o:-" $1 +} + +function create () { + local LEVEL=$1 + if [ $LEVEL -eq 0 ]; then + local I=0 + while [ $I -lt $FILES ]; do + random_file file$I + I=$[$I+1] + done + echo -n "." + else + local I=0 + while [ $I -lt $DIRS ]; do + random_dir dir$I + cd dir$I + create $[$LEVEL-1] + cd .. + I=$[$I+1] + done + fi + return +} + +mkdir -p tree +cd tree +create $LEVELS +cd .. +echo + diff --git a/test/src/asroot.test b/test/src/asroot.test new file mode 100644 index 0000000..f719470 --- /dev/null +++ b/test/src/asroot.test @@ -0,0 +1,49 @@ +! +! Test that can only be run as root as it uses mknod. +! +$mkdir asroot +$ umask 027 +$ mknod asroot/null c 1 3 +$ mode asroot/null +crw-r----- +$ setfacl -m u:joe:rw,u:lisa:- asroot/null +$ mode asroot/null +crw-rw----+ +$ su -c cat\ asroot/null lisa +cat: asroot/null: Permission denied +$ setfacl -m u:lisa:r asroot/null +$ getfacl --omit-header asroot/null +user::rw- +user:lisa:r-- +user:joe:rw- +group::r-- +mask:rw- +other:--- + +$ su lisa -c cat\ asroot/null +$ su lisa -c echo\ abc\ >asroot/null +bash: asroot/null: Permission denied +$ rm -f asroot/null +$ mkfifo asroot/fifo +$ mode asroot/fifo +prw-r----- +$ setfacl -m u:joe:- asroot/fifo +$ getfacl --omit-header asroot/fifo +user::rw- +user:joe:--- +group::r-- +mask:r-- +other:--- + +$ rm asroot/fifo +$ mknod asroot/block b 1 1 +$ setfacl -m u:joe:- asroot/block +$ getfacl --omit-header asroot/block +user::rw- +user:joe:--- +group::r-- +mask:r-- +other:--- + +$ rm asroot/block +$ rmdir asroot diff --git a/test/src/echo_into b/test/src/echo_into new file mode 100644 index 0000000..536e957 --- /dev/null +++ b/test/src/echo_into @@ -0,0 +1,2 @@ +#!/bin/sh +if test -n "$1" -a -n "$2" ; then echo $1 > $2; fi diff --git a/test/src/fileutil.test b/test/src/fileutil.test new file mode 100644 index 0000000..3c28396 --- /dev/null +++ b/test/src/fileutil.test @@ -0,0 +1,66 @@ +! +! Test for the patched file utilities. +! +$ umask 022 +$ mkdir dir +$ mode dir +drwxr-xr-x +$ touch dir/f +$ getfacl -c dir/f +user::rw- +group::r-- +other:r-- + +$ umask 027 +$ cp -p dir/f dir/g +$ getfacl -c dir/g +user::rw- +group::r-- +other:r-- + +$ rm dir/g +$ cp dir/f dir/g +$ getfacl -c dir/g +user::rw- +group::r-- +other:--- + +$ setfacl -m u::rwx,u:joe:rwx,g::rwx,o:r-x dir/. +$ setfacl -dm u::rwx,u:joe:rwx,g::rwx,o:r-x dir/. +$ mode dir +drwxrwxr-x+ +$ touch dir/h +$ getfacl -cE dir/h +user::rw- +user:joe:rwx +group::rwx +mask:rw- +other:r-- + +$ mkdir dir/d +$ getfacl -cE dir/d +user::rwx +user:joe:rwx +group::rwx +mask:rwx +other:r-x +default:user::rwx +default:user:joe:rwx +default:group::rwx +default:mask:rwx +default:other:r-x + +$ cp dir/f dir/i +$ getfacl -cE dir/i +user::rw- +user:joe:rwx +group::rwx +mask:r-- +other:r-- + +$ mode dir/f +-rw-r--r-- +$ cp -p dir/f dir/j +$ mode dir/j +-rw-r--r-- +$ rm -r dir diff --git a/test/src/getfacl-noacl.test b/test/src/getfacl-noacl.test new file mode 100644 index 0000000..d27981f --- /dev/null +++ b/test/src/getfacl-noacl.test @@ -0,0 +1,96 @@ +! +! getfacl test on a filesystem without ACLs +! +! This test must be run on a filesystem with or without ACL support. +! +$ mkdir test +$ cd test +$ umask 027 +$ touch x +$ getfacl x +# file: x +# owner: @OWNER@ +# group: @GROUP@ +user::rw- +group::r-- +other::--- + +$ getfacl --omit-header -a x +user::rw- +group::r-- +other::--- + +$ getfacl --omit-header -d x +$ getfacl --omit-header -d . +$ getfacl --omit-header -d / +getfacl: Removing leading '/' from absolute path names +$ getfacl --skip-base x +$ getfacl --omit-header --all-effective x +user::rw- +group::r-- +other::--- + +$ getfacl --omit-header --no-effective x +user::rw- +group::r-- +other::--- + +$ mkdir d +$ touch d/y +$ ln -s d l +$ getfacl -dR . +# file: . +# owner: @OWNER@ +# group: @GROUP@ + +# file: x +# owner: @OWNER@ +# group: @GROUP@ + +# file: d +# owner: @OWNER@ +# group: @GROUP@ + +# file: d/y +# owner: @OWNER@ +# group: @GROUP@ + +$ getfacl -dLR . +# file: . +# owner: @OWNER@ +# group: @GROUP@ + +# file: x +# owner: @OWNER@ +# group: @GROUP@ + +# file: d +# owner: @OWNER@ +# group: @GROUP@ + +# file: d/y +# owner: @OWNER@ +# group: @GROUP@ + +# file: l +# owner: @OWNER@ +# group: @GROUP@ + +# file: l/y +# owner: @OWNER@ +# group: @GROUP@ + +$ getfacl --post-order -d d +# file: d/y +# owner: @OWNER@ +# group: @GROUP@ + +# file: d +# owner: @OWNER@ +# group: @GROUP@ + +$ rm l +$ rm -rf d +$ rm x +$ cd .. +$ rmdir test diff --git a/test/src/misc.test b/test/src/misc.test new file mode 100644 index 0000000..a2bad7f --- /dev/null +++ b/test/src/misc.test @@ -0,0 +1,384 @@ +! +! Pretty comprehensive ACL tests. +! +! This must be run on a filesystem with ACL support. Also, you will need +! two dummy users (lisa and joe) and a dummy group (toolies). +! +$ umask 027 +$ touch f +$ setfacl -m u:lisa:rw f +$ mode f +-rw-rw----+ +$ getfacl --omit-header f +user::rw- +user:lisa:rw- +group::r-- +mask::rw- +other::--- + +$ rm f +$ umask 022 +$ touch f +$ setfacl -m u:lisa:rw f +$ mode f +-rw-rw-r--+ +$ getfacl --omit-header f +user::rw- +user:lisa:rw- +group::r-- +mask::rw- +other::r-- + +$rm f +$ umask 027 +$ mkdir d +$ setfacl -m u:lisa:rwx d +$ mode d +drwxrwx---+ +$ getfacl --omit-header d +user::rwx +user:lisa:rwx +group::r-x +mask::rwx +other::--- + +$ rmdir d +$ umask 022 +$ mkdir d +$ setfacl -m u:lisa:rwx d +$ mode d +drwxrwxr-x+ +$ getfacl --omit-header d +user::rwx +user:lisa:rwx +group::r-x +mask::rwx +other::r-x + +$ rmdir d +! +! Multiple users +! +$ umask 022 +$ touch f +$ setfacl -m u:lisa:rw,u:joe:r f +$ mode f +-rw-rw-r--+ +$ getfacl --omit-header f +user::rw- +user:lisa:rw- +user:joe:r-- +group::r-- +mask::rw- +other::r-- + +! +! Multiple groups +! +$ setfacl -m g:users:rw,g:toolies:r f +$ mode f +-rw-rw-r--+ +$ getfacl --omit-header f +user::rw- +user:lisa:rw- +user:joe:r-- +group::r-- +group:users:rw- +group:toolies:r-- +mask::rw- +other::r-- + +! +! Remove one group +! +$ setfacl -x g:users f +$ mode f +-rw-rw-r--+ +$ getfacl --omit-header f +user::rw- +user:lisa:rw- +user:joe:r-- +group::r-- +group:toolies:r-- +mask::rw- +other::r-- + +! +! Remove one user +! +$ setfacl -x u:joe f +$ mode f +-rw-rw-r--+ +$ getfacl --omit-header f +user::rw- +user:lisa:rw- +group::r-- +group:toolies:r-- +mask::rw- +other::r-- + +$ rm f +! +! Default ACL +! +$ umask 027 +$ mkdir d +$ setfacl -m u:lisa:rwx,u:joe:rw,d:u:lisa:rwx,d:m:rx d +$ mode d +drwxrwx---+ +$ getfacl --omit-header d +user::rwx +user:lisa:rwx +user:joe:rw- +group::r-x +mask::rwx +other::--- +default:user::rwx +default:user:lisa:rwx #effective:r-x +default:group::r-x +default:mask::r-x +default:other::--- + +! +! Umask now ignored? +! +$ umask 027 +$ touch d/f +$ mode d/f +-rw-r-----+ +$ getfacl --omit-header d/f +user::rw- +user:lisa:rwx #effective:r-- +group::r-x #effective:r-- +mask::r-- +other::--- + +$ rm d/f +$ umask 022 +$ touch d/f +$ mode d/f +-rw-r-----+ +$ getfacl --omit-header d/f +user::rw- +user:lisa:rwx #effective:r-- +group::r-x #effective:r-- +mask::r-- +other::--- + +$ rm d/f +! +! Default ACL copying +! +$ umask 000 +$ mkdir d/d +$ mode d/d +drwxr-x---+ +$ getfacl --omit-header d/d +user::rwx +user:lisa:rwx #effective:r-x +group::r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:rwx #effective:r-x +default:group::r-x +default:mask::r-x +default:other::--- + +$ rmdir d/d +$ umask 022 +$ mkdir d/d +$ mode d/d +drwxr-x---+ +$ getfacl --omit-header d/d +user::rwx +user:lisa:rwx #effective:r-x +group::r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:rwx #effective:r-x +default:group::r-x +default:mask::r-x +default:other::--- + +! +! Add some users and groups +! +$ setfacl -nm u:joe:rx,d:u:joe:rx,g:users:rx,g:toolies:rwx d/d +$ mode d/d +drwxr-x---+ +$ getfacl --omit-header d/d +user::rwx +user:lisa:rwx #effective:r-x +user:joe:r-x +group::r-x +group:users:r-x +group:toolies:rwx #effective:r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:rwx #effective:r-x +default:user:joe:r-x +default:group::r-x +default:mask::r-x +default:other::--- + +! +! symlink in directory with default ACL? +! +$ ln -s d d/l +$ mode d/l +lrwxrwxrwx +$ mode -L d/l +drwxr-x---+ +$ getfacl --omit-header d/l +user::rwx +user:lisa:rwx #effective:r-x +user:joe:r-x +group::r-x +group:users:r-x +group:toolies:rwx #effective:r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:rwx #effective:r-x +default:user:joe:r-x +default:group::r-x +default:mask::r-x +default:other::--- + +$ rm d/l +! +! Does mask manipulation work? +! +$ setfacl -m g:toolies:rx,u:lisa:rx d/d +$ mode d/d +drwxr-x---+ +$ getfacl --omit-header d/d +user::rwx +user:lisa:r-x +user:joe:r-x +group::r-x +group:users:r-x +group:toolies:r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:rwx #effective:r-x +default:user:joe:r-x +default:group::r-x +default:mask::r-x +default:other::--- + +$ setfacl -m d:u:lisa:rwx d/d +$ mode d/d +drwxr-x---+ +$ getfacl --omit-header d/d +user::rwx +user:lisa:r-x +user:joe:r-x +group::r-x +group:users:r-x +group:toolies:r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:rwx +default:user:joe:r-x +default:group::r-x +default:mask::rwx +default:other::--- + +$ rmdir d/d +! +! Remove the default ACL +! +$ setfacl -k d +$ mode d +drwxrwx---+ +$ getfacl --omit-header d +user::rwx +user:lisa:rwx +user:joe:rw- +group::r-x +mask::rwx +other::--- + +! +! Reset to base entries +! +$ setfacl -b d +$ mode d +drwxr-x--- +$ getfacl --omit-header d +user::rwx +group::r-x +other::--- + +! +! Now, chmod should change the group_obj entry +! +$ chmod 775 d +$ mode d +drwxrwxr-x +$ getfacl --omit-header d +user::rwx +group::rwx +other::r-x + +$ rmdir d +$ umask 002 +$ mkdir d +$ setfacl -m u:joe:rwx,u:lisa:rx,d:u:joe:rwx,d:u:lisa:rx d +$ mode d +drwxrwxr-x+ +$ getfacl --omit-header d +user::rwx +user:lisa:r-x +user:joe:rwx +group::rwx +mask::rwx +other::r-x +default:user::rwx +default:user:lisa:r-x +default:user:joe:rwx +default:group::rwx +default:mask::rwx +default:other::r-x + +$ chmod 750 d +$ mode d +drwxr-x---+ +$ getfacl --omit-header d +user::rwx +user:lisa:r-x +user:joe:rwx #effective:r-x +group::rwx #effective:r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:r-x +default:user:joe:rwx +default:group::rwx +default:mask::rwx +default:other::r-x + +$ chmod 750 d +$ mode d +drwxr-x---+ +$ getfacl --omit-header d +user::rwx +user:lisa:r-x +user:joe:rwx #effective:r-x +group::rwx #effective:r-x +mask::r-x +other::--- +default:user::rwx +default:user:lisa:r-x +default:user:joe:rwx +default:group::rwx +default:mask::rwx +default:other::r-x + +$ rmdir d diff --git a/test/src/mode b/test/src/mode new file mode 100644 index 0000000..af4b5eb --- /dev/null +++ b/test/src/mode @@ -0,0 +1,2 @@ +#!/bin/sh +ls -dl $* | awk -- '!/^total/ { print $1; }' diff --git a/test/src/perm.test b/test/src/perm.test new file mode 100644 index 0000000..b849a19 --- /dev/null +++ b/test/src/perm.test @@ -0,0 +1,17 @@ +! +! Test whether ACL permissions work +! +$ umask 022 +$ mkdir dir +$ umask 077 +$ ./echo_into inside dir/file +$ setfacl -m u:joe:rw,u:lisa:- dir/file +$ su lisa -c cat\ dir/file +cat: dir/file: Permission denied +$ su joe -c cat\ dir/file +inside +$ su joe -c ./echo_into\ out\ dir/file +$ cat dir/file +out +$ rm dir/file +$ rmdir dir diff --git a/test/src/prepare-tests b/test/src/prepare-tests new file mode 100644 index 0000000..b6503ef --- /dev/null +++ b/test/src/prepare-tests @@ -0,0 +1,5 @@ +#!/bin/sh + +grep ^toolies: /etc/group >/dev/null || groupadd toolies +grep ^lisa: /etc/passwd >/dev/null || useradd -g toolies lisa +grep ^joe: /etc/passwd >/dev/null || useradd -g toolies joe diff --git a/test/src/run b/test/src/run new file mode 100644 index 0000000..a371a27 --- /dev/null +++ b/test/src/run @@ -0,0 +1,150 @@ +#!/usr/bin/perl + +use strict; +use FileHandle; +use POSIX qw(geteuid getegid isatty); + +my $owner = getpwuid(geteuid()); +my $group = getgrgid(getegid()); + +my ($OK, $FAILED) = ("ok", "failed"); +if (isatty(fileno(STDOUT))) { + $OK = "\033[32m" . $OK . "\033[m"; + $FAILED = "\033[31m\033[1m" . $FAILED . "\033[m"; +} + +my ($prog, $in, $out) = ([], [], []); +my $line = 0; +my $prog_line; +for (;;) { + my $script = <>; $line++; + $script =~ s/\@OWNER\@/$owner/g; + $script =~ s/\@GROUP\@/$group/g; + next if (defined($script) && $script =~ /^!/); + if (!defined($script) || $script =~ s/^\$ ?//) { + if (@$prog) { + #print "[$prog_line] \$ ", join(' ', @$prog), " -- "; + my $p = [ @$prog ]; + print "[$prog_line] \$ ", join(' ', + map { s/\s/\\$&/g; $_ } @$p), " -- "; + my $result = exec_test($prog, $in); + my $good = 1; + my $nmax = (@$out > @$result) ? @$out : @$result; + for (my $n=0; $n < $nmax; $n++) { + if (!defined($out->[$n]) || !defined($result->[$n]) || + $out->[$n] ne $result->[$n]) { + $good = 0; + #chomp $out->[$n]; + #chomp $result->[$n]; + #print "$out->[$n] != $result->[$n]"; + } + } + print $good ? $OK : $FAILED, "\n"; + if (!$good) { + for (my $n=0; $n < $nmax; $n++) { + my $l = defined($out->[$n]) ? $out->[$n] : "~"; + chomp $l; + my $r = defined($result->[$n]) ? $result->[$n] : "~"; + chomp $r; + print sprintf("%-37s | %-39s\n", $l, $r); + } + } + } + #$prog = [ split /\s+/, $script ] if $script; + $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $script ] if $script; + #$prog = $script; + #chomp $prog; + $prog_line = $line; + $in = []; + $out = []; + } elsif ($script =~ s/^> ?//) { + push @$in, $script; + } else { + push @$out, $script; + } + last unless defined($script); +} + +sub exec_test($$) { + my ($prog, $in) = @_; + local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2); + + if ($prog->[0] eq "umask") { + umask oct $prog->[1]; + return []; + } elsif ($prog->[0] eq "cd") { + if (!chdir $prog->[1]) { + return [ "chdir: " . $prog->[1] . ": $!\n" ]; + } + return []; + } + + pipe *IN2, *OUT + or die "Can't create pipe for reading: $!"; + open *IN_DUP, "<&STDIN" + or *IN_DUP = undef; + open *STDIN, "<&IN2" + or die "Can't duplicate pipe for reading: $!"; + close *IN2; + + open *OUT_DUP, ">&STDOUT" + or die "Can't duplicate STDOUT: $!"; + pipe *IN, *OUT2 + or die "Can't create pipe for writing: $!"; + open *STDOUT, ">&OUT2" + or die "Can't duplicate pipe for writing: $!"; + close *OUT2; + + *STDOUT->autoflush(); + *OUT->autoflush(); + + if (fork()) { + # Server + if (*IN_DUP) { + open *STDIN, "<&IN_DUP" + or die "Can't duplicate STDIN: $!"; + close *IN_DUP + or die "Can't close STDIN duplicate: $!"; + } + open *STDOUT, ">&OUT_DUP" + or die "Can't duplicate STDOUT: $!"; + close *OUT_DUP + or die "Can't close STDOUT duplicate: $!"; + + foreach my $line (@$in) { + #print "> $line"; + print OUT $line; + } + close *OUT + or die "Can't close pipe for writing: $!"; + + my $result = []; + while (<IN>) { + #print "< $_"; + push @$result, $_; + } + return $result; + } else { + # Client + close IN + or die "Can't close read end for input pipe: $!"; + close OUT + or die "Can't close write end for output pipe: $!"; + close OUT_DUP + or die "Can't close STDOUT duplicate: $!"; + local *ERR_DUP; + open ERR_DUP, ">&STDERR" + or die "Can't duplicate STDERR: $!"; + open STDERR, ">&STDOUT" + or die "Can't join STDOUT and STDERR: $!"; + + #print ERR_DUP "<", join(' ', @$prog), ">\n"; + #my $c = join(' ', @$prog); + #$c =~ s/\\/\\\\/; + #exec ('/bin/sh', '-c', $c); + exec (@$prog); + print ERR_DUP $prog->[0], ": $!\n"; + exit; + } +} + diff --git a/test/src/setfacl-noacl.test b/test/src/setfacl-noacl.test new file mode 100644 index 0000000..33c2bdb --- /dev/null +++ b/test/src/setfacl-noacl.test @@ -0,0 +1,65 @@ +! +! setfacl tests. +! +! Run these tests on a filesystem without ACL support. +! +$ umask 027 +$ touch f +$ mode f +-rw-r----- +$ setfacl -m g::- f +$ mode f +-rw------- +$ setfacl -m g::+rw f +$ mode f +-rw-rw---- +$ setfacl -m g::^w f +$ mode f +-rw-r----- +$ setfacl -m u:: f +setfacl: Option -m incomplete +$ setfacl -s o:---,g::---,u::--- f +$ mode f +---------- +$ setfacl -s user::rw,group::r,other:- f +$ mode f +-rw-r----- +$ setfacl -x u:root f +$ setfacl -x mask f +$ setfacl -x default:user f +$ setfacl -b f +$ setfacl -m u:joe:rw f +setfacl: f: Operation not supported +$ setfacl -m u::rwx,g::r-x,o:- f +$ mode f +-rwxr-x--- +$ getfacl --omit-header f +user::rwx +group::r-x +other:--- + +$ setfacl -m u::rwx,g::r-x,o:-,m:- f +setfacl: f: Operation not supported +$ setfacl --test -x u: f +setfacl: f: Resulting ACL `group::r-x,other:---': Missing or wrong entry at entry 1 +$ setfacl --test -x u:x f +setfacl: Option -x: Invalid argument near character 3 +$ rm f +$mkdir d +$ setfacl -m d:u:root:rwx d +setfacl: d: Operation not supported +$ setfacl --test -x m d +# file: d +# owner: @OWNER@ +# group: @GROUP@ +# (acl unchanged) +# (default acl unchanged) + +$ setfacl --test -dx m d +# file: d +# owner: @OWNER@ +# group: @GROUP@ +# (acl unchanged) +# (default acl unchanged) + +$rmdir d diff --git a/test/src/setfacl.test b/test/src/setfacl.test new file mode 100644 index 0000000..94b157d --- /dev/null +++ b/test/src/setfacl.test @@ -0,0 +1,110 @@ +! +! setfacl tests. +! +! Run these tests on a filesystem with ACL support. +! +$ umask 027 +$ touch g +$ mode g +-rw-r----- +$ setfacl -m m:- g +$ mode g +-rw-------+ +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rw- +group::r-- #effective:--- +mask::--- +other::--- + +$ setfacl -x m g +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rw- +group::r-- +other::--- + +$ setfacl -m u:joe:rw g +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rw- +user:joe:rw- +group::r-- +mask::rw- +other::--- + +$ setfacl -m u::rwx,g::r-x,o:- g +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rwx +user:joe:rw- +group::r-x +mask::rwx +other::--- + +$ setfacl -m u::rwx,g::r-x,o:-,m:- g +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rwx +user:joe:rw- #effective:--- +group::r-x #effective:--- +mask::--- +other::--- + +$ setfacl -m u::rwx,g::r-x,o:-,u:root:-,m:- g +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rwx +user:root:--- +user:joe:rw- #effective:--- +group::r-x #effective:--- +mask::--- +other::--- + +$ setfacl -m u::rwx,g::r-x,o:-,u:root:-,m:- g +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rwx +user:root:--- +user:joe:rw- #effective:--- +group::r-x #effective:--- +mask::--- +other::--- + +$ setfacl -m u::rwx,g::r-x,o:-,u:root:- g +$ getfacl g +# file: g +# owner: @OWNER@ +# group: @GROUP@ +user::rwx +user:root:--- +user:joe:rw- +group::r-x +mask::rwx +other::--- + +$ setfacl --test -x u: g +setfacl: g: Resulting ACL `user:root:---,user:joe:rw-,group::r-x,mask::rwx,other::---': Missing or wrong entry at entry 1 +$ setfacl --test -x u:x +setfacl: Option -x: Invalid argument near character 3 +$ setfacl -m d:u:root:rwx g +setfacl: g: Only directories can have a default ACL +$ setfacl -x m g +setfacl: g: Resulting ACL `user::rwx,user:root:---,user:joe:rw-,group::r-x,other::---': Missing or wrong entry at entry 5 +!setfacl --test -m d:u:joe:rwx setfacl +!setfacl --test -n -m d:u:joe:rwx setfacl +$ rm g diff --git a/test/stress/do-n b/test/stress/do-n new file mode 100644 index 0000000..26548f9 --- /dev/null +++ b/test/stress/do-n @@ -0,0 +1,10 @@ +N=$1 +shift +echo $* +I=0 +while [ $I -lt $N ]; do + echo -n "$I " + `echo $* | sed -e "s/%/$I/g"` + I=$[$I+1] +done + diff --git a/test/stress/loop1 b/test/stress/loop1 new file mode 100644 index 0000000..7a7b5c3 --- /dev/null +++ b/test/stress/loop1 @@ -0,0 +1,13 @@ +#!/bin/sh +test -z "$1" -o -z "$2" && exit + +while [ 1 == 1 ]; do + ./stress1 $1 + ./stress2 $2 + ./stress3 $1 + ./stress4 $2 + + rm -rf $1/* + rm -rf $2/* +done + diff --git a/test/stress/loop2 b/test/stress/loop2 new file mode 100644 index 0000000..db71bac --- /dev/null +++ b/test/stress/loop2 @@ -0,0 +1,14 @@ +#!/bin/sh +test -z "$1" -o -z "$2" && exit + +while [ 1 == 1 ]; do + ./stress1 $1 + rm -rf $1/* + ./stress2 $2 + rm -rf $2/* + ./stress3 $1 + rm -rf $2/* + ./stress4 $2 + rm -rf $2/* +done + diff --git a/test/stress/loop3 b/test/stress/loop3 new file mode 100644 index 0000000..6f42fea --- /dev/null +++ b/test/stress/loop3 @@ -0,0 +1,14 @@ +#!/bin/sh +test -z "$1" -o -z "$2" && exit + +while [ 1 == 1 ]; do + ./stress4 $2 + ./stress3 $1 + rm -rf $1/* + rm -rf $2/* + ./stress2 $2 + ./stress1 $1 + rm -rf $1/* + rm -rf $2/* +done + diff --git a/test/stress/loop4 b/test/stress/loop4 new file mode 100644 index 0000000..127c066 --- /dev/null +++ b/test/stress/loop4 @@ -0,0 +1,8 @@ +#!/bin/sh +test -z "$1" && exit + +while [ 1 == 1 ]; do + ./stress5 $1 + rm -rf $1/* +done + diff --git a/test/stress/loop5 b/test/stress/loop5 new file mode 100644 index 0000000..e8fd74d --- /dev/null +++ b/test/stress/loop5 @@ -0,0 +1,7 @@ +#!/bin/sh +test -z "$1" && exit + +while [ 1 == 1 ]; do + ./stress6 $1 r1 +done + diff --git a/test/stress/loop6 b/test/stress/loop6 new file mode 100644 index 0000000..75df6d2 --- /dev/null +++ b/test/stress/loop6 @@ -0,0 +1,7 @@ +#!/bin/sh +test -z "$1" && exit + +while [ 1 == 1 ]; do + ./stress6 $1 w1 +done + diff --git a/test/stress/lsloop b/test/stress/lsloop new file mode 100644 index 0000000..c28d957 --- /dev/null +++ b/test/stress/lsloop @@ -0,0 +1,20 @@ +#!/bin/sh +while [ 1 == 1 ]; do + echo d + ls -lr d >/dev/null + sleep 1 + echo d2 + ls -lr d2 >/dev/null + sleep 1 + echo d3 + ls -lr d3 >/dev/null + sleep 1 + echo d4 + ls -lr d4 >/dev/null + sleep 1 + ls -lr d5 >/dev/null + sleep 1 + ls -lr d6 >/dev/null + sleep 1 +done + diff --git a/test/stress/show b/test/stress/show new file mode 100644 index 0000000..e6fb290 --- /dev/null +++ b/test/stress/show @@ -0,0 +1,9 @@ +#!/bin/bash +I=1 +while [ 1 -eq 1 ]; do + echo "------------------------------------- ($I)" + cat /proc/fs/acl-cache + sleep 1 + I=$[$I+1] +done + diff --git a/test/stress/some.acl b/test/stress/some.acl new file mode 100644 index 0000000..06e3279 --- /dev/null +++ b/test/stress/some.acl @@ -0,0 +1,115 @@ +# file: d1 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:group::r-x +default:other:--- + +# file: d2 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:user:joe:rwx +default:group::r-x +default:mask:rwx +default:other:r-x + +# file: d3 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:user:lisa:rwx +default:group::r-x +default:mask:rwx +default:other:r-x + +# file: d4 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:user:mark:rwx +default:group::r-x +default:mask:rwx +default:other:r-x + +# file: d5 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:user:ag:rwx +default:group::r-x +default:mask:rwx +default:other:r-x + +# file: d6 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:user:lisa:rwx +default:group::r-x +default:mask:rwx +default:other:r-x + +# file: d7 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:user:tom:rwx +default:user:joe:rwx +default:group::r-x +default:mask:rwx +default:other:r-x + +# file: d8 +# owner: agruenba +# group: users +user::rwx +group::r-x +other:r-x +default:user::rwx +default:user:lisa:r-x +default:user:joe:rwx +default:user:mark:rwx +default:group::r-x +default:mask:rwx +default:other:r-x + +# file: d9 +# owner: agruenba +# group: users +user::rwx +user:tom:r-x +user:joe:r-x +user:mark:r-x +group::r-x +mask:r-x +other:r-x +default:user::rwx +default:user:tom:r-x +default:user:joe:r-x +default:user:mark:r-x +default:group::r-x +default:mask:r-x +default:other:r-x + diff --git a/test/stress/stress1 b/test/stress/stress1 new file mode 100644 index 0000000..8728cf0 --- /dev/null +++ b/test/stress/stress1 @@ -0,0 +1,11 @@ +test -n "$1" || exit + +I=0 +while [ "$I" -lt 1000 ]; do + N=`printf %03d $I` + echo -n "$N " + touch $1/f$N + I=$[$I+1] +done +echo + diff --git a/test/stress/stress2 b/test/stress/stress2 new file mode 100644 index 0000000..0fb6da1 --- /dev/null +++ b/test/stress/stress2 @@ -0,0 +1,13 @@ +test -n "$1" || exit + +I=0 +while [ "$I" -lt 1000 ]; do + N=`printf %03d $I` + echo -n "$N " + touch $1/f$N + setfacl -m g:toolies:rw $1/f$N + setfacl -x g:toolies $1/f$N + setfacl -m u:joe:rw,u:mark:rw,u:lisa:r,g:toolies:r $1/f$N + I=$[$I+1] +done +echo diff --git a/test/stress/stress3 b/test/stress/stress3 new file mode 100644 index 0000000..a2848b4 --- /dev/null +++ b/test/stress/stress3 @@ -0,0 +1,12 @@ +test -n "$1" || exit + +I=0 +while [ "$I" -lt 1000 ]; do + N=`printf %03d $I` + echo -n "$N " + mkdir $1/d$N + touch $1/d$N/f$N + I=$[$I+1] +done +echo + diff --git a/test/stress/stress4 b/test/stress/stress4 new file mode 100644 index 0000000..fcd4fbd --- /dev/null +++ b/test/stress/stress4 @@ -0,0 +1,12 @@ +test -n "$1" || exit + +I=0 +while [ "$I" -lt 1000 ]; do + N=`printf %03d $I` + echo -n "$N " + mkdir $1/d$N + touch $1/d$N/f$N + setfacl -m u:$[$I+1000]:rw $1/d$N/f$N + I=$[$I+1] +done +echo diff --git a/test/stress/stress5 b/test/stress/stress5 new file mode 100644 index 0000000..816fa35 --- /dev/null +++ b/test/stress/stress5 @@ -0,0 +1,27 @@ +test -n "$1" || exit + +I=0 +K=0 +while [ "$I" -lt 1000 ]; do + N=`printf %03d $I` + echo -n "$N " + touch $1/f$N + setfacl -m u:$[$K+1000]:rw $1/f$N + I=$[$I+1] + K=$[$K+1] + if [ $K -eq 20 ]; then + K=0 + fi +done +echo + +I=0 +while [ "$I" -lt 10000 ]; do + X=`printf %03d $[$RANDOM % 1000]` + Y=`printf %03d $[$RANDOM % 1000]` + echo -n "$I " + getfacl $1/f$X | setfacl -S- $1/f$Y + I=$[$I+1] +done +echo + diff --git a/test/stress/stress6 b/test/stress/stress6 new file mode 100644 index 0000000..d97cd5a --- /dev/null +++ b/test/stress/stress6 @@ -0,0 +1,21 @@ +test -n "$1" -a -n "$2" || exit + +I=0 +case $2 in + (r*) + touch $1/$2 + while [ $I -lt 10000 ]; do + echo -n "$I " + I=$[$I + 1] + cat $1/$2 + done ;; + (w*) + while [ $I -lt 5000 ]; do + echo -n "$I " + I=$[$I + 1] + touch $1/$2 + rm $1/$2 + done +esac +echo + |