diff options
author | Robert Watson <rwatson@FreeBSD.org> | 2001-03-19 18:09:25 +0000 |
---|---|---|
committer | Robert Watson <rwatson@FreeBSD.org> | 2001-03-19 18:09:25 +0000 |
commit | 43960f159d60217fcb3c5c03095effdb77a0f291 (patch) | |
tree | f856eed97626f278dbf77e26f5302d36edbc68d0 /bin | |
parent | f74abb9b6e332f32005a7f8c108f7292b35d5452 (diff) |
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
Notes
Notes:
svn path=/head/; revision=74465
Diffstat (limited to 'bin')
-rw-r--r-- | bin/getfacl/getfacl.1 | 100 | ||||
-rw-r--r-- | bin/getfacl/getfacl.c | 201 | ||||
-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 |
10 files changed, 1284 insertions, 0 deletions
diff --git a/bin/getfacl/getfacl.1 b/bin/getfacl/getfacl.1 new file mode 100644 index 000000000000..20d0906da0f7 --- /dev/null +++ b/bin/getfacl/getfacl.1 @@ -0,0 +1,100 @@ +.\"- +.\" Copyright (c) 2000 Robert N. M. Watson +.\" 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 CONTRIBUTORS 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 March 30, 2000 +.Dt GETFACL 1 +.Os +.Sh NAME +.Nm getfacl +.Nd Get ACL Information +.Sh SYNOPSIS +.Nm getfacl +.Op Fl d +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm +utility writes discretionary access control information associated with +the specified file(s) to standard output. +If the +.Xr getconf 8 +utility indicates that +.Va {_POSIX_ACL_EXTENDED} +is not in effect for a +.Ar file +then the standard discretionary access permissions are interpreted as +an ACL containing only the required ACL entries. +.Pp +The following option is available: +.Bl -tag -width indent +.It Fl d +The operation applies to the default ACL of a directory instead of the +access ACL. +An error shall be generated if a default ACL cannot be associated with +.Op Ar file . +.El +.Pp +The following operand is available: +.Bl -tag -width indent +.It Ar file +A pathname of a file whose ACL shall be retrieved. +If +.Op Ar file +is not specified, or a +.Op Ar file +is specified as "-", then +.Nm +shall read a list of pathnames, each terminated by one <newline> character, +from the standard input. +.El +.Pp +.Sh EXAMPLES +.Pp +.Dl getfacl / +.Pp +Retrieve ACL for the directory "/". +.Pp +.Dl getfacl -d / +.Pp +Retrieve the default ACL for the directory "/", if any. +.Sh SEE ALSO +.Xr setfacl 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 +Robert N M Watson diff --git a/bin/getfacl/getfacl.c b/bin/getfacl/getfacl.c new file mode 100644 index 000000000000..638d26d89af6 --- /dev/null +++ b/bin/getfacl/getfacl.c @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 1999-2001 Robert N M Watson + * 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 CONTRIBUTORS 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$ + */ +/* + * getfacl -- POSIX.1e utility to extract ACLs from files and directories + * and send the results to stdout + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/acl.h> +#include <sys/stat.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +int more_than_one = 0; + +static void +usage(void) +{ + + fprintf(stderr, "getfacl [-d] [files ...]\n"); +} + +static acl_t +acl_from_stat(struct stat sb) +{ + acl_t acl; + + acl = acl_init(3); + if (!acl) + return(NULL); + + acl->acl_entry[0].ae_tag = ACL_USER_OBJ; + acl->acl_entry[0].ae_id = sb.st_uid; + acl->acl_entry[0].ae_perm = 0; + if (sb.st_mode & S_IRUSR) + acl->acl_entry[0].ae_perm |= ACL_PERM_READ; + if (sb.st_mode & S_IWUSR) + acl->acl_entry[0].ae_perm |= ACL_PERM_WRITE; + if (sb.st_mode & S_IXUSR) + acl->acl_entry[0].ae_perm |= ACL_PERM_EXEC; + + acl->acl_entry[1].ae_tag = ACL_GROUP_OBJ; + acl->acl_entry[1].ae_id = sb.st_gid; + acl->acl_entry[1].ae_perm = 0; + if (sb.st_mode & S_IRGRP) + acl->acl_entry[1].ae_perm |= ACL_PERM_READ; + if (sb.st_mode & S_IWGRP) + acl->acl_entry[1].ae_perm |= ACL_PERM_WRITE; + if (sb.st_mode & S_IXGRP) + acl->acl_entry[1].ae_perm |= ACL_PERM_EXEC; + + acl->acl_entry[2].ae_tag = ACL_OTHER_OBJ; + acl->acl_entry[2].ae_id = 0; + acl->acl_entry[2].ae_perm = 0; + if (sb.st_mode & S_IROTH) + acl->acl_entry[2].ae_perm |= ACL_PERM_READ; + if (sb.st_mode & S_IWOTH) + acl->acl_entry[2].ae_perm |= ACL_PERM_WRITE; + if (sb.st_mode & S_IXOTH) + acl->acl_entry[2].ae_perm |= ACL_PERM_EXEC; + + acl->acl_cnt = 3; + + return(acl); +} + +static int +print_acl(char *path, acl_type_t type) +{ + struct stat sb; + acl_t acl; + char *acl_text; + int error; + + error = stat(path, &sb); + if (error == -1) { + perror(path); + return(-1); + } + + if (more_than_one) + printf("\n"); + else + more_than_one++; + + printf("#file:%s\n#owner:%d\n#group:%d\n", path, sb.st_uid, sb.st_gid); + + acl = acl_get_file(path, type); + if (!acl) { + if (errno != EOPNOTSUPP) { + warn("%s", path); + return(-1); + } + errno = 0; + if (type != ACL_TYPE_ACCESS) + return(0); + acl = acl_from_stat(sb); + if (!acl) { + perror("acl_from_stat()"); + return(-1); + } + } + + acl_text = acl_to_text(acl, 0); + if (!acl_text) { + perror(path); + return(-1); + } + + printf("%s", acl_text); + + acl_free(acl); + acl_free(acl_text); + + return(0); +} + +static int +print_acl_from_stdin(acl_type_t type) +{ + char pathname[PATH_MAX]; + int carried_error = 0; + + pathname[sizeof(pathname) - 1] = '\0'; + while (fgets(pathname, sizeof(pathname), stdin)) { + /* remove the \n */ + pathname[strlen(pathname) - 1] = '\0'; + if (print_acl(pathname, type) == -1) { + carried_error = -1; + } + } + + return(carried_error); +} + +int +main(int argc, char *argv[]) +{ + acl_type_t type = ACL_TYPE_ACCESS; + int carried_error = 0; + int ch, error, i; + + while ((ch = getopt(argc, argv, "d")) != -1) + switch(ch) { + case 'd': + type = ACL_TYPE_DEFAULT; + break; + default: + usage(); + return(-1); + } + argc -= optind; + argv += optind; + + if (argc == 0) { + error = print_acl_from_stdin(type); + return(error); + } + + for (i = 0; i < argc; i++) { + if (!strcmp(argv[i], "-")) { + error = print_acl_from_stdin(type); + if (error == -1) + carried_error = -1; + } else { + error = print_acl(argv[i], type); + if (error == -1) + carried_error = -1; + } + } + + return(carried_error); +} 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; +} |