diff options
Diffstat (limited to 'bin/setfacl')
-rw-r--r-- | bin/setfacl/Makefile | 11 | ||||
-rw-r--r-- | bin/setfacl/file.c | 74 | ||||
-rw-r--r-- | bin/setfacl/mask.c | 100 | ||||
-rw-r--r-- | bin/setfacl/merge.c | 113 | ||||
-rw-r--r-- | bin/setfacl/remove.c | 155 | ||||
-rw-r--r-- | bin/setfacl/setfacl.1 | 229 | ||||
-rw-r--r-- | bin/setfacl/setfacl.c | 254 | ||||
-rw-r--r-- | bin/setfacl/util.c | 47 |
8 files changed, 983 insertions, 0 deletions
diff --git a/bin/setfacl/Makefile b/bin/setfacl/Makefile new file mode 100644 index 000000000000..3556b1ac0b60 --- /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 000000000000..776efdcb3492 --- /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 000000000000..5992e9435e3b --- /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 000000000000..c739b26cd50f --- /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 000000000000..0fe02d17e1c7 --- /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 000000000000..fe28f86df963 --- /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 000000000000..c18c3f90c610 --- /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 000000000000..25144213dfe9 --- /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; +} |