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
This commit is contained in:
Robert Watson 2001-03-19 18:09:25 +00:00
parent f74abb9b6e
commit 43960f159d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=74465
10 changed files with 1284 additions and 0 deletions

100
bin/getfacl/getfacl.1 Normal file
View File

@ -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

201
bin/getfacl/getfacl.c Normal file
View File

@ -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);
}

11
bin/setfacl/Makefile Normal file
View File

@ -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>

74
bin/setfacl/file.c Normal file
View File

@ -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);
}

100
bin/setfacl/mask.c Normal file
View File

@ -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;
}

113
bin/setfacl/merge.c Normal file
View File

@ -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;
}

155
bin/setfacl/remove.c Normal file
View File

@ -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;
}

229
bin/setfacl/setfacl.1 Normal file
View File

@ -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 .

254
bin/setfacl/setfacl.c Normal file
View File

@ -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;
}

47
bin/setfacl/util.c Normal file
View File

@ -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;
}