summaryrefslogtreecommitdiffstats
path: root/bin/setfacl
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2001-03-19 18:09:25 +0000
committerrwatson <rwatson@FreeBSD.org>2001-03-19 18:09:25 +0000
commit4978ee9a87e5510a56defc3e556c4a2c31a7bdc4 (patch)
treea21327f2f0786874aabdb6afb6408653ae46e0b6 /bin/setfacl
parentd98c5293d7c959bbef954c5c8e9c97d67138634f (diff)
downloadFreeBSD-src-4978ee9a87e5510a56defc3e556c4a2c31a7bdc4.zip
FreeBSD-src-4978ee9a87e5510a56defc3e556c4a2c31a7bdc4.tar.gz
o POSIX.2c Userland tool support for POSIX.1e ACLs -- getfacl retrieves ACLs
from files and directories, and setfacl sets ACLs on files and directories. Submitted by: jedgar Obtained from: TrustedBSD Project
Diffstat (limited to 'bin/setfacl')
-rw-r--r--bin/setfacl/Makefile11
-rw-r--r--bin/setfacl/file.c74
-rw-r--r--bin/setfacl/mask.c100
-rw-r--r--bin/setfacl/merge.c113
-rw-r--r--bin/setfacl/remove.c155
-rw-r--r--bin/setfacl/setfacl.1229
-rw-r--r--bin/setfacl/setfacl.c254
-rw-r--r--bin/setfacl/util.c47
8 files changed, 983 insertions, 0 deletions
diff --git a/bin/setfacl/Makefile b/bin/setfacl/Makefile
new file mode 100644
index 0000000..3556b1a
--- /dev/null
+++ b/bin/setfacl/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+CFLAGS+= -g ${BDECFLAGS}
+
+PROG= setfacl
+SRCS= file.c mask.c merge.c remove.c setfacl.c util.c
+LDADD= -lposix1e
+
+NOSHARED= yes
+
+.include <bsd.prog.mk>
diff --git a/bin/setfacl/file.c b/bin/setfacl/file.c
new file mode 100644
index 0000000..776efdc
--- /dev/null
+++ b/bin/setfacl/file.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "setfacl.h"
+
+/* read acl text from a file and return the corresponding acl */
+acl_t
+get_acl_from_file(const char *filename)
+{
+ FILE *file;
+ char buf[BUFSIZ];
+
+ if (!filename)
+ err(EX_USAGE, "(null) filename in get_acl_from_file()");
+
+ bzero(&buf, sizeof(buf));
+
+ if (!strcmp(filename, "-")) {
+ if (have_stdin)
+ err(EX_USAGE, "cannot specify more than one stdin");
+ file = stdin;
+ have_stdin = 1;
+ } else {
+ file = fopen(filename, "r");
+ if (!file)
+ err(EX_OSERR, "fopen() %s failed", filename);
+ }
+
+ fread(buf, sizeof(buf), 1, file);
+ if (ferror(file)) {
+ fclose(file);
+ err(EX_USAGE, "error reading from %s", filename);
+ } else if (!feof(file)) {
+ fclose(file);
+ errx(EX_USAGE, "line too long in %s", filename);
+ }
+
+ fclose(file);
+
+ return acl_from_text(buf);
+}
diff --git a/bin/setfacl/mask.c b/bin/setfacl/mask.c
new file mode 100644
index 0000000..5992e94
--- /dev/null
+++ b/bin/setfacl/mask.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+
+#include "setfacl.h"
+
+/* set the appropriate mask the given ACL's */
+int
+set_acl_mask(acl_t prev_acl)
+{
+ acl_t acl;
+ int i;
+
+ /*
+ * ... if a mask entry is specified, then the permissions of the mask
+ * entry in the resulting ACL shall be set to the permissions in the
+ * specified ACL mask entry.
+ */
+ if (have_mask)
+ return 0;
+
+ acl = acl_dup(prev_acl);
+ if (!acl)
+ err(EX_OSERR, "acl_dup() failed");
+
+ if (!n_flag) {
+ /*
+ * If no mask entry is specified and the -n option is not
+ * specified, then the permissions of the resulting ACL mask
+ * entry shall be set to the union of the permissions
+ * associated with all entries which belong to the file group
+ * class in the resulting ACL
+ */
+ if (acl_calc_mask(&acl)) {
+ warn("acl_calc_mask() failed");
+ acl_free(acl);
+ return -1;
+ }
+ } else {
+ /*
+ * If no mask entry is specified and the -n option is
+ * specified, then the permissions of the resulting ACL
+ * mask entry shall remain unchanged ...
+ */
+ for (i = 0; i < acl->acl_cnt; i++)
+ if (acl->acl_entry[i].ae_tag == ACL_MASK) {
+ acl_free(acl);
+ return 0;
+ }
+
+ /*
+ * If no mask entry is specified, the -n option is specified,
+ * and no ACL mask entry exists in the ACL associated with the
+ * file, then write an error message to standard error and
+ * continue with the next file.
+ */
+ warnx("warning: no mask entry");
+ acl_free(acl);
+ return 0;
+ }
+
+ *prev_acl = *acl;
+ acl_free(acl);
+
+ return 0;
+}
diff --git a/bin/setfacl/merge.c b/bin/setfacl/merge.c
new file mode 100644
index 0000000..c739b26
--- /dev/null
+++ b/bin/setfacl/merge.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <sysexits.h>
+
+#include "setfacl.h"
+
+/* merge acl into existing file's ACL */
+int
+merge_acl(acl_t acl, acl_t *prev_acl)
+{
+ acl_t acl_new;
+ int blank_acl_user, blank_acl_group, have_entry, i, j;
+ struct stat sb;
+
+ blank_acl_user = blank_acl_group = 0;
+
+ if (acl_type == ACL_TYPE_ACCESS)
+ acl_new = acl_dup(prev_acl[0]);
+ else
+ acl_new = acl_dup(prev_acl[1]);
+ if (!acl_new)
+ err(EX_OSERR, "acl_dup() failed");
+
+ /* step through new ACL entries */
+ for (i = 0; i < acl->acl_cnt; i++) {
+ have_entry = 0;
+
+ /* oh look, we have an ACL_MASK entry */
+ if (acl->acl_entry[i].ae_tag == ACL_MASK)
+ have_mask = 1;
+
+ /* check against the existing ACL entries */
+ for (j = 0; j < acl_new->acl_cnt && !have_entry; j++) {
+ if (acl_new->acl_entry[j].ae_tag ==
+ acl->acl_entry[i].ae_tag) {
+ switch(acl->acl_entry[i].ae_tag) {
+ case ACL_USER_OBJ:
+ acl_new->acl_entry[j].ae_perm =
+ acl->acl_entry[i].ae_perm;
+ acl_new->acl_entry[j].ae_id = sb.st_uid;
+ have_entry = 1;
+ break;
+ case ACL_GROUP_OBJ:
+ acl_new->acl_entry[j].ae_perm =
+ acl->acl_entry[i].ae_perm;
+ acl_new->acl_entry[j].ae_id = sb.st_gid;
+ have_entry = 1;
+ break;
+ default:
+ if (acl_new->acl_entry[j].ae_id ==
+ acl->acl_entry[i].ae_id) {
+ /* any other matches */
+ acl_new->acl_entry[j].ae_perm =
+ acl->acl_entry[i].ae_perm;
+ have_entry = 1;
+ }
+ break;
+ }
+ }
+ }
+
+ /* if this entry has not been found, it must be new */
+ if (!have_entry) {
+ if (acl_new->acl_cnt == ACL_MAX_ENTRIES) {
+ warn("too many ACL entries");
+ acl_free(acl_new);
+ return -1;
+ }
+ acl_new->acl_entry[acl_new->acl_cnt++] =
+ acl->acl_entry[i];
+ }
+ }
+
+ if (acl_type == ACL_TYPE_ACCESS)
+ *prev_acl[0] = *acl_new;
+ else
+ *prev_acl[1] = *acl_new;
+ acl_free(acl_new);
+
+ return 0;
+}
diff --git a/bin/setfacl/remove.c b/bin/setfacl/remove.c
new file mode 100644
index 0000000..0fe02d1
--- /dev/null
+++ b/bin/setfacl/remove.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "setfacl.h"
+
+/* remove ACL entries from an ACL */
+int
+remove_acl(acl_t acl, acl_t *prev_acl)
+{
+ acl_t acl_new;
+ int carried_error, i;
+
+ carried_error = 0;
+
+ if (acl_type == ACL_TYPE_ACCESS)
+ acl_new = acl_dup(prev_acl[0]);
+ else
+ acl_new = acl_dup(prev_acl[1]);
+ if (!acl_new)
+ err(EX_OSERR, "acl_dup() failed");
+
+ /* find and delete the entry */
+ for (i = 0; i < acl->acl_cnt; i++) {
+ if (acl->acl_entry[i].ae_tag == ACL_MASK)
+ have_mask++;
+ if (acl_delete_entry(acl_new, &acl->acl_entry[i]) == -1) {
+ carried_error++;
+ warnx("cannot remove non-existent acl entry");
+ }
+ }
+
+ if (acl_type == ACL_TYPE_ACCESS) {
+ acl_free(prev_acl[0]);
+ prev_acl[0] = acl_new;
+ } else {
+ acl_free(prev_acl[1]);
+ prev_acl[1] = acl_new;
+ }
+
+ if (carried_error)
+ return -1;
+
+ return 0;
+}
+
+/* remove default entries */
+int
+remove_default(acl_t *prev_acl)
+{
+
+ if (prev_acl[1]) {
+ bzero(prev_acl[1], sizeof(struct acl));
+ prev_acl[1]->acl_cnt = 0;
+ } else {
+ warn("cannot remove default ACL");
+ return -1;
+ }
+ return 0;
+}
+
+/* remove extended entries */
+void
+remove_ext(acl_t *prev_acl)
+{
+ acl_t acl_new, acl_old;
+ acl_perm_t group_perm, mask_perm;
+ int have_mask_entry, i;
+
+ if (acl_type == ACL_TYPE_ACCESS)
+ acl_old = acl_dup(prev_acl[0]);
+ else
+ acl_old = acl_dup(prev_acl[1]);
+ if (!acl_old)
+ err(EX_OSERR, "acl_dup() failed");
+
+ group_perm = mask_perm = 0;
+ have_mask_entry = 0;
+ acl_new = acl_init(ACL_MAX_ENTRIES);
+ if (!acl_new)
+ err(EX_OSERR, "%s", "acl_init() failed");
+
+ /* only save the default user/group/other entries */
+ for (i = 0; i < acl_old->acl_cnt; i++)
+ switch(acl_old->acl_entry[i].ae_tag) {
+ case ACL_USER_OBJ:
+ acl_new->acl_entry[0] = acl_old->acl_entry[i];
+ break;
+ case ACL_GROUP_OBJ:
+ acl_new->acl_entry[1] = acl_old->acl_entry[i];
+ group_perm = acl_old->acl_entry[i].ae_perm;
+ break;
+ case ACL_OTHER_OBJ:
+ acl_new->acl_entry[2] = acl_old->acl_entry[i];
+ break;
+ case ACL_MASK:
+ mask_perm = acl_old->acl_entry[i].ae_perm;
+ have_mask_entry = 1;
+ break;
+ default:
+ break;
+ }
+ /*
+ * If the ACL contains a mask entry, then the permissions associated
+ * with the owning group entry in the resulting ACL shall be set to
+ * only those permissions associated with both the owning group entry
+ * and the mask entry of the current ACL.
+ */
+ if (have_mask_entry)
+ acl_new->acl_entry[1].ae_perm = group_perm & mask_perm;
+ acl_new->acl_cnt = 3;
+
+ if (acl_type == ACL_TYPE_ACCESS) {
+ acl_free(prev_acl[0]);
+ prev_acl[0] = acl_new;
+ } else {
+ acl_free(prev_acl[1]);
+ prev_acl[1] = acl_new;
+ }
+
+ have_mask = 0;
+}
diff --git a/bin/setfacl/setfacl.1 b/bin/setfacl/setfacl.1
new file mode 100644
index 0000000..fe28f86
--- /dev/null
+++ b/bin/setfacl/setfacl.1
@@ -0,0 +1,229 @@
+.\"
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 7, 2001
+.Dt SETFACL 1
+.Os
+.Sh NAME
+.Nm setfacl
+.Nd Set ACL Information
+.Sh SYNOPSIS
+.Nm setfacl
+.Op Fl bdkn
+.Op Fl m Ar entries
+.Op Fl M Ar file1
+.Op Fl x Ar entries
+.Op Fl X Ar file1
+.Op Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility sets discretionary access control information on
+the specified file(s).
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl b
+Remove all ACL entries except for the three required entries.
+.It Fl d
+The operations apply to the default ACL entries instead of
+access ACL entries. Currently only directories may have
+default ACL's.
+.It Fl k
+Delete any default ACL entries on the specified files. It
+is not considered an error if the specified files do not have
+any default ACL entries. An error will be reported if any of
+the specified files cannot have a default entry (i.e.
+non-directories).
+.It Fl m Ar entries
+Modify the ACL entries on the specified files by adding new
+entries and modifying existing ACL entries with the ACL entries
+specified in
+.Ar entries .
+.It Fl M Ar file
+Modify the ACL entries on the specified files by adding new
+ACL entries and modifying existing ACL entries with the ACL
+entries specified in the file
+.Ar file .
+If
+.Ar file
+is "-", the input is taken from stdin.
+.It Fl n
+Do not recalculate the permissions associated with the ACL
+mask entry.
+.It Fl x Ar entries
+Remove the ACL entries specified in
+.Ar entries
+from the access or default ACL of the specified files.
+.It Fl X Ar file
+Remove the ACL entries specified in the file
+.Ar file
+from the access or default ACL of the specified files.
+.El
+.Pp
+The above options are evaluated in the order specified
+on the command-line.
+.Pp
+Multiple ACL entries specified on the command line shall be
+separated by commas.
+.Sh ACL ENTRIES
+An ACL entry shall contain three colon-separated fields:
+an ACL tag, an ACL qualifier, and discretionary access
+permissions:
+.Pp
+.Bl -tag -width indent
+.It Ar ACL tag
+The ACL tag specifies the ACL entry type and shall consist of
+one of the following: ``user'' or ``u'' specifying the access
+granted to the owner of the file or a specified user; ``group''
+or ``g'' specifying the access granted to the file owning group
+or a specified group; ``other'' or ``o'' specifying the access
+granted to any process that does not match any user or group
+ACL entry; ``mask'' or ``m'' specifying the maximum access
+granted to any ACL entry except the
+.Ar user
+ACL entry for the file owner and the
+.Ar other
+ACL entry.
+.Pp
+.It Ar ACL qualifier
+The ACL qualifier field describes the user or group associated with
+the ACL entry. It may consist of one of the following: uid or
+user name, gid or group name, or empty. For
+.Ar user
+ACL entries, an empty field shall specify access granted to the
+file owner. For
+.Ar group
+ACL entries, an empty field shall specify access granted to the
+file owning group.
+.Ar mask
+and
+.Ar other
+ACL entries do not use this field.
+.Pp
+.It Ar access permissions
+The access permissions field shall contain up to one of each of
+the following: ``r'', ``w'', and ``x'' to set read, write, and
+execute permissions, respectively. Each of these may be excluded
+or replaced with a ``-'' character to indicate no access.
+.El
+.Pp
+A
+.Ar mask
+ACL entry is required on a file with any ACL entries other than
+the default
+.Ar user ,
+.Ar group ,
+and
+.Ar other
+ACL entries. If the
+.Fl n
+option is not specified and no
+.Ar mask
+ACL entry was specified, the
+.Nm
+utility
+will apply a
+.Ar mask
+ACL entry consisting of the union of the permissions associated
+with all
+.Ar group
+ACL entries in the resulting ACL.
+.Pp
+ACL entries applied from a file using the
+.Fl M
+or
+.Fl X
+options shall be of the following form: one ACL entry per line, as
+previously specified; whitespace is ignored; any text after a # is
+ignored (comments).
+.Pp
+When ACL entries are evaluated, the access check algorithm checks
+the ACL entries in the following order: file owner,
+.Ar user
+ACL entries, file owning group,
+.Ar group
+ACL entries, and
+.Ar other
+ACL entry.
+.Sh RETURN VALUES
+The
+.Nm
+utility returns 0 on success and > 0 if an error occurs.
+.Sh EXAMPLES
+.Dl setfacl -m u::rwx,g:mail:rw file
+.Pp
+Sets read, write, and execute permissions for the
+.Pa file
+owner's ACL entry and read and write permissions for group mail on
+.Pa file .
+.Pp
+.Dl setfacl -M file1 file2
+.Pp
+Sets/updates the ACL entries contained in
+.Pa file1
+on
+.Pa file2 .
+.Pp
+.Dl setfacl -x g:mail:rw file
+.Pp
+Remove the group mail ACL entry containing read/write permissions
+from
+.Pa file.
+.Pp
+.Dl setfacl -b file
+.Pp
+Remove all ACL entries except for the three required
+entries from
+.Pa file .
+.Pp
+.Dl getfacl file1 | setfacl -b -n -M - file2
+.Pp
+Copy ACL entries from
+.Pa file1
+to
+.Pa file2 .
+.Sh SEE ALSO
+.Xr getfacl 1 ,
+.Xr acl 3 ,
+.Xr getextattr 8 ,
+.Xr setextattr 8 ,
+.Xr acl 9 ,
+.Xr extattr 9 .
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be IEEE Std 1003.2c compliant.
+.Sh HISTORY
+Extended Attribute and Access Control List support was developed
+as part of the TrustedBSD Project and introduced in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Nm
+utility was written by
+.An Chris D. Faulhaber Aq jedgar@fxp.org .
diff --git a/bin/setfacl/setfacl.c b/bin/setfacl/setfacl.c
new file mode 100644
index 0000000..c18c3f9
--- /dev/null
+++ b/bin/setfacl/setfacl.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/acl.h>
+#include <sys/queue.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "setfacl.h"
+
+static void add_filename(const char *filename);
+static acl_t *get_file_acls(const char *filename);
+static void usage(void);
+
+static void
+add_filename(const char *filename)
+{
+ struct sf_file *file;
+
+ if (strlen(filename) > PATH_MAX - 1) {
+ warn("illegal filename");
+ return;
+ }
+ file = zmalloc(sizeof(struct sf_file));
+ file->filename = filename;
+ STAILQ_INSERT_TAIL(&filelist, file, next);
+}
+
+static acl_t *
+get_file_acls(const char *filename)
+{
+ acl_t *acl;
+ struct stat sb;
+
+ if (stat(filename, &sb) == -1) {
+ warn("stat() of %s failed", filename);
+ return NULL;
+ }
+
+ acl = zmalloc(sizeof(acl_t) * 2);
+ acl[0] = acl_get_file(filename, ACL_TYPE_ACCESS);
+ if (!acl[0])
+ err(EX_OSERR, "acl_get_file() failed");
+ if (S_ISDIR(sb.st_mode)) {
+ acl[1] = acl_get_file(filename, ACL_TYPE_DEFAULT);
+ if (!acl[1])
+ err(EX_OSERR, "acl_get_file() failed");
+ } else
+ acl[1] = NULL;
+
+ return acl;
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: setfacl [-bdknv] [-m entries] [-M file1] "
+ "[-x entries] [-X file2] [file ...]\n");
+ exit(EX_USAGE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ acl_t *acl, final_acl;
+ char filename[PATH_MAX];
+ int local_error, carried_error, ch, i;
+ struct sf_file *file;
+ struct sf_entry *entry;
+
+ acl_type = ACL_TYPE_ACCESS;
+ carried_error = local_error = 0;
+ have_mask = have_stdin = n_flag = need_mask = 0;
+
+ STAILQ_INIT(&entrylist);
+ STAILQ_INIT(&filelist);
+
+ while ((ch = getopt(argc, argv, "M:X:bdkm:nx:")) != -1)
+ switch(ch) {
+ case 'M':
+ entry = zmalloc(sizeof(struct sf_entry));
+ entry->acl = get_acl_from_file(optarg);
+ if (!entry->acl)
+ err(EX_OSERR, "get_acl_from_file() failed");
+ entry->op = OP_MERGE_ACL;
+ STAILQ_INSERT_TAIL(&entrylist, entry, next);
+ break;
+ case 'X':
+ entry = zmalloc(sizeof(struct sf_entry));
+ entry->acl = get_acl_from_file(optarg);
+ entry->op = OP_REMOVE_ACL;
+ STAILQ_INSERT_TAIL(&entrylist, entry, next);
+ break;
+ case 'b':
+ entry = zmalloc(sizeof(struct sf_entry));
+ entry->op = OP_REMOVE_EXT;
+ STAILQ_INSERT_TAIL(&entrylist, entry, next);
+ break;
+ case 'd':
+ acl_type = ACL_TYPE_DEFAULT;
+ break;
+ case 'k':
+ entry = zmalloc(sizeof(struct sf_entry));
+ entry->op = OP_REMOVE_DEF;
+ STAILQ_INSERT_TAIL(&entrylist, entry, next);
+ break;
+ case 'm':
+ entry = zmalloc(sizeof(struct sf_entry));
+ entry->acl = acl_from_text(optarg);
+ if (!entry->acl)
+ err(EX_USAGE, "acl_from_text() failed");
+ entry->op = OP_MERGE_ACL;
+ STAILQ_INSERT_TAIL(&entrylist, entry, next);
+ break;
+ case 'n':
+ n_flag++;
+ break;
+ case 'x':
+ entry = zmalloc(sizeof(struct sf_entry));
+ entry->acl = acl_from_text(optarg);
+ if (!entry->acl)
+ err(EX_USAGE, "acl_from_text() failed");
+ entry->op = OP_REMOVE_ACL;
+ STAILQ_INSERT_TAIL(&entrylist, entry, next);
+ break;
+ default:
+ usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (STAILQ_EMPTY(&entrylist))
+ usage();
+
+ /* take list of files from stdin */
+ if (argc == 0 || !strcmp(argv[0], "-")) {
+ if (have_stdin)
+ err(EX_USAGE, "cannot have more than one stdin");
+ have_stdin = 1;
+ bzero(&filename, sizeof(filename));
+ while (fgets(filename, sizeof(filename), stdin)) {
+ /* remove the \n */
+ filename[strlen(filename) - 1] = '\0';
+ add_filename(filename);
+ }
+ } else
+ for (i = 0; i < argc; i++)
+ add_filename(argv[i]);
+
+ /* cycle through each file */
+ STAILQ_FOREACH(file, &filelist, next) {
+ /* get our initial access and default ACL's */
+ acl = get_file_acls(file->filename);
+ if (!acl)
+ continue;
+ if ((acl_type == ACL_TYPE_DEFAULT) && !acl[1]) {
+ warnx("Default ACL not valid for %s", file->filename);
+ continue;
+ }
+
+ local_error = 0;
+
+ /* cycle through each option */
+ STAILQ_FOREACH(entry, &entrylist, next) {
+ if (local_error)
+ continue;
+
+ switch(entry->op) {
+ case OP_MERGE_ACL:
+ local_error += merge_acl(entry->acl, acl);
+ need_mask = 1;
+ break;
+ case OP_REMOVE_EXT:
+ remove_ext(acl);
+ need_mask = 0;
+ break;
+ case OP_REMOVE_DEF:
+ if (acl_delete_def_file(file->filename) == -1) {
+ warn("acl_delete_def_file() failed");
+ local_error++;
+ }
+ local_error += remove_default(acl);
+ need_mask = 0;
+ break;
+ case OP_REMOVE_ACL:
+ local_error += remove_acl(entry->acl, acl);
+ need_mask = 1;
+ break;
+ /* NOTREACHED */
+ }
+ }
+
+ /* don't bother setting the ACL if something is broken */
+ if (local_error) {
+ carried_error++;
+ continue;
+ }
+
+ if (acl_type == ACL_TYPE_ACCESS)
+ final_acl = acl[0];
+ else
+ final_acl = acl[1];
+
+ if (need_mask && (set_acl_mask(final_acl) == -1)) {
+ warnx("failed to set ACL mask on %s", file->filename);
+ carried_error++;
+ } else if (acl_set_file(file->filename, acl_type,
+ final_acl) == -1) {
+ carried_error++;
+ warn("acl_set_file() failed for %s", file->filename);
+ }
+
+ acl_free(acl[0]);
+ acl_free(acl[1]);
+ free(acl);
+ }
+
+ return carried_error;
+}
diff --git a/bin/setfacl/util.c b/bin/setfacl/util.c
new file mode 100644
index 0000000..2514421
--- /dev/null
+++ b/bin/setfacl/util.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "setfacl.h"
+
+void *
+zmalloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (!ptr)
+ err(EX_OSERR, "malloc() failed");
+ bzero(ptr, size);
+
+ return ptr;
+}
OpenPOWER on IntegriCloud