Add mask recomputation as on Linux

* setfacl.c: Align more to Linux tool.
        (delacl): New function to delete acl entries only.
        (modacl): Drop delete functionality.  Add handling of recomputing the
        mask and default mask values.
        (delallacl): Rename from delacl.
        (setfacl): Call delacl in Delete case.  Call delallacl in DeleteAll
        and DeleteDef case.
        (usage): Accommodate new options.  Rearrange and rephrase slightly.
        (longopts): Emit 'x' in --delete case.  Add --no-mask and --mask
        options.
        (opts): Add -x and -n options.
        (main): Handle -d and -x the same.  Handle -n and --mask options.
        Drop handling for -r option.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2015-04-16 17:57:53 +02:00
parent bd57946148
commit baacff7c79
4 changed files with 314 additions and 181 deletions

View File

@ -1,3 +1,7 @@
2015-04-16 Corinna Vinschen <corinna@vinschen.de>
* utils.xml (setfacl): Show new option output.
2015-04-16 Corinna Vinschen <corinna@vinschen.de> 2015-04-16 Corinna Vinschen <corinna@vinschen.de>
* utils.xml (getfacl): Show new option output. * utils.xml (getfacl): Show new option output.

View File

@ -1698,34 +1698,31 @@ Example: regtool.exe get '\user\software\Microsoft\Clock\iFormat'
<title>setfacl</title> <title>setfacl</title>
<screen> <screen>
Usage: setfacl [-r] {-f ACL_FILE | -s acl_entries} FILE... Usage: %s {-f ACL_FILE | -s acl_entries} FILE...\n"
setfacl [-r] {-b|[-d acl_entries] [-m acl_entries]} FILE... %s {-b|[-x acl_entries] [-m acl_entries]} FILE...\n"
Modify file and directory access control lists (ACLs)\n"
Modify file and directory access control lists (ACLs) -b, --remove-all remove all extended ACL entries\n"
-x, --delete delete one or more specified ACL entries\n"
-f, --file set ACL entries for FILE to ACL entries read\n"
from ACL_FILE\n"
-k, --remove-default remove all default ACL entries\n"
-m, --modify modify one or more specified ACL entries\n"
-n, --no-mask don't recalculate the effective rights mask\n"
--mask do recalculate the effective rights mask\n"
-s, --substitute substitute specified ACL entries on FILE\n"
-V, --version print version and exit\n"
-h, --help this help text\n"
-b, --remove-all remove all extended ACL entries At least one of (-b, -x, -f, -k, -m, -s) must be specified\n"
-d, --delete delete one or more specified ACL entries
-f, --file set ACL entries for FILE to ACL entries read
from a ACL_FILE
-k, --remove-default
remove all default ACL entries
-m, --modify modify one or more specified ACL entries
-r, --replace replace mask entry with maximum permissions
needed for the file group class
-s, --substitute substitute specified ACL entries for the
ACL of FILE
-h, --help output usage information and exit
-V, --version output version information and exit
At least one of (-b, -d, -f, -k, -m, -s) must be specified
</screen> </screen>
<para> For each file given as parameter, <command>setfacl</command> will <para> For each file given as parameter, <command>setfacl</command> will
either replace its complete ACL (<literal>-s</literal>, either replace its complete ACL (<literal>-s</literal>,
<literal>-f</literal>), or it will add, modify, or delete ACL entries. <literal>-f</literal>), or it will add, modify, or delete ACL entries.
For more information on Cygwin and Windows ACLs, see see <xref For more information on Cygwin and Windows ACLs, see
linkend="ntsec"/> in the Cygwin User's Guide. </para> <xref linkend="ntsec"/> in the Cygwin User's Guide. </para>
<para> Acl_entries are one or more comma-separated ACL entries from the <para> Acl_entries are one or more comma-separated ACL entries from the
following list: following list:
@ -1752,13 +1749,14 @@ At least one of (-b, -d, -f, -k, -m, -s) must be specified
<para> The following options are supported: </para> <para> The following options are supported: </para>
<para> <literal>-b</literal> Remove all extended ACL entries. The base <para> <literal>-b</literal>,<literal>--remove-all</literal> Remove all
ACL entries of the owner, group and others are retained.</para> extended ACL entries. The base ACL entries of the owner, group and
others are retained.</para>
<para> <literal>-d</literal> Delete one or more specified entries from the <para> <literal>-x</literal>,<literal>--delete</literal> Delete one or
file's ACL. The owner, group and others entries must not be deleted. more specified entries from the file's ACL. The owner, group and others
Acl_entries to be deleted should be specified without permissions, as in entries must not be deleted. Acl_entries to be deleted should be
the following list: specified without permissions, as in the following list:
<screen> <screen>
u[ser]:uid[:] u[ser]:uid[:]
g[roup]:gid[:] g[roup]:gid[:]
@ -1769,11 +1767,12 @@ At least one of (-b, -d, -f, -k, -m, -s) must be specified
d[efault]:o[ther][:] d[efault]:o[ther][:]
</screen> </para> </screen> </para>
<para> <literal>-f</literal> Take the Acl_entries from ACL_FILE one per <para> <literal>-f</literal>,<literal>--file</literal> Take the Acl_entries
line. Whitespace characters are ignored, and the character "#" may be from ACL_FILE one per line. Whitespace characters are ignored, and the
used to start a comment. The special filename "-" indicates reading from character "#" may be used to start a comment. The special filename "-"
stdin. Note that you can use this with <command>getfacl</command> and indicates reading from stdin. Note that you can use this with
<command>setfacl</command> to copy ACLs from one file to another: <command>getfacl</command> and <command>setfacl</command> to copy ACLs
from one file to another:
<screen> <screen>
$ getfacl source_file | setfacl -f - target_file $ getfacl source_file | setfacl -f - target_file
</screen> </para> </screen> </para>
@ -1789,22 +1788,31 @@ $ getfacl source_file | setfacl -f - target_file
file, one default group entry for the group of the file, one default mask file, one default group entry for the group of the file, one default mask
entry for the file group class, and one default other entry. </para> entry for the file group class, and one default other entry. </para>
<para> <literal>-k</literal> Remove all default ACL entries. If no default <para> <literal>-k</literal>,<literal>--remove-default</literal> Remove all
ACL entries exist, no warnings are issued. </para> default ACL entries. If no default ACL entries exist, no warnings are
issued. </para>
<para> <literal>-m</literal> Add or modify one or more specified ACL <para> <literal>-m</literal>,<literal>--modify</literal> Add or modify one
entries. Acl_entries is a comma-separated list of entries from the same or more specified ACL entries. Acl_entries is a comma-separated list of
list as above. </para> entries from the same list as above. </para>
<para> <literal>-r</literal> Causes the permissions specified in the mask <para> <literal>-n</literal>,<literal>--no-mask</literal> Valid in
entry to be ignored and replaced by the maximum permissions needed for conjunction with -m. Do not recalculate the effective rights mask.
the file group class. </para> The default behavior of setfacl is to recalculate the ACL mask entry,
unless a mask entry was explicitly given. The mask entry is set to
the union of all permissions of the owning group, and all named user
and group entries. (These are exactly the entries affected by the
mask entry). </para>
<para> <literal>-s</literal> Like <literal>-f</literal>, but substitute the <para> <literal>--mask</literal> Valid in conjunction with -m. Do
file's ACL with Acl_entries specified in a comma-separated list on the recalculate the effective rights mask, even if an ACL mask entry was
command line. </para> explicitly given. (See the -n option.) </para>
<para> While the <literal>-d</literal> and <literal>-m</literal> options <para> <literal>-s</literal>,<literal>--substitute</literal> Like
<literal>-f</literal>, but substitute the file's ACL with Acl_entries
specified in a comma-separated list on the command line. </para>
<para> While the <literal>-x</literal> and <literal>-m</literal> options
may be used in the same command, the <literal>-f</literal> and may be used in the same command, the <literal>-f</literal> and
<literal>-s</literal> options may be used only exclusively. </para> <literal>-s</literal> options may be used only exclusively. </para>

View File

@ -1,3 +1,19 @@
2015-04-16 Corinna Vinschen <corinna@vinschen.de>
* setfacl.c: Align more to Linux tool.
(delacl): New function to delete acl entries only.
(modacl): Drop delete functionality. Add handling of recomputing the
mask and default mask values.
(delallacl): Rename from delacl.
(setfacl): Call delacl in Delete case. Call delallacl in DeleteAll
and DeleteDef case.
(usage): Accommodate new options. Rearrange and rephrase slightly.
(longopts): Emit 'x' in --delete case. Add --no-mask and --mask
options.
(opts): Add -x and -n options.
(main): Handle -d and -x the same. Handle -n and --mask options.
Drop handling for -r option.
2015-04-16 Corinna Vinschen <corinna@vinschen.de> 2015-04-16 Corinna Vinschen <corinna@vinschen.de>
* getfacl.c (usage): Align more closely to Linux version. Add new * getfacl.c (usage): Align more closely to Linux version. Add new

View File

@ -1,7 +1,7 @@
/* setfacl.c /* setfacl.c
Copyright 2000, 2001, 2002, 2003, 2006, 2008, 2009, 2010, 2011, 2014 Copyright 2000, 2001, 2002, 2003, 2006, 2008, 2009, 2010, 2011, 2014,
Red Hat Inc. 2015 Red Hat Inc.
Written by Corinna Vinschen <vinschen@redhat.com> Written by Corinna Vinschen <vinschen@redhat.com>
@ -53,6 +53,8 @@ typedef enum {
SetFromFile SetFromFile
} action_t; } action_t;
int mask_opt = 0;
mode_t getperm (char *in) mode_t getperm (char *in)
{ {
if (isdigit ((unsigned char) *in) && !in[1]) if (isdigit ((unsigned char) *in) && !in[1])
@ -239,7 +241,7 @@ searchace (aclent_t *aclp, int nentries, int type, int id)
} }
int int
modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt) delacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt)
{ {
int t, s, i; int t, s, i;
@ -249,8 +251,6 @@ modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt)
(src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1); (src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1);
if (t < 0) if (t < 0)
return -1; return -1;
if (src[s].a_perm == ILLEGAL_MODE)
{
if (t < tcnt) if (t < tcnt)
{ {
for (i = t + 1; i < tcnt; ++i) for (i = t + 1; i < tcnt; ++i)
@ -258,13 +258,105 @@ modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt)
--tcnt; --tcnt;
} }
} }
else return tcnt;
}
int
modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt)
{ {
int t, s;
int recompute_mask = 0, recompute_def_mask = 0;
int need_mask = 0, need_def_mask = 0;
int has_mask = 0, has_def_mask = 0;
int mask_idx = -1, def_mask_idx = -1;
mode_t mask = 0, def_mask = 0;
/* Replace or add given acl entries. */
for (s = 0; s < scnt; ++s)
{
t = searchace (tgt, MAX_ACL_ENTRIES, src[s].a_type,
(src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1);
if (t < 0)
return -1;
tgt[t] = src[s]; tgt[t] = src[s];
if (t >= tcnt) if (t >= tcnt)
++tcnt; ++tcnt;
/* Note if CLASS_OBJ and/or DEF_CLASS_OBJ are present in input. */
if (src[s].a_type == CLASS_OBJ)
has_mask = 1;
else if (src[s].a_type == DEF_CLASS_OBJ)
has_def_mask = 1;
else if (src[s].a_type & ACL_DEFAULT)
recompute_def_mask = 1;
else
recompute_mask = 1;
}
/* Now recompute mask, if requested (default) */
for (t = 0; t < tcnt; ++t)
{
switch (tgt[t].a_type)
{
case USER:
case GROUP:
/* Do we need a CLASS_OBJ at all? */
need_mask = 1;
/*FALLTHRU*/
case GROUP_OBJ:
/* Compute resulting maximum mask. */
mask |= tgt[t].a_perm;
break;
case CLASS_OBJ:
/* Do we already have a CLASS_OBJ? */
mask_idx = t;
break;
case DEF_USER:
case DEF_GROUP:
/* Do we need a DEF_CLASS_OBJ at all? */
need_def_mask = 1;
/*FALLTHRU*/
case DEF_GROUP_OBJ:
/* Compute resulting maximum default mask. */
def_mask |= tgt[t].a_perm;
break;
case DEF_CLASS_OBJ:
/* Do we already have a DEF_CLASS_OBJ? */
def_mask_idx = t;
break;
} }
} }
/* Recompute mask, if requested */
if (recompute_mask && need_mask && mask_opt >= 0
&& (mask_opt > 0 || !has_mask))
{
if (mask_idx >= 0)
t = mask_idx;
else
t = searchace (tgt, MAX_ACL_ENTRIES, CLASS_OBJ, -1);
if (t < 0)
return -1;
if (t >= tcnt)
++tcnt;
tgt[t].a_type = CLASS_OBJ;
tgt[t].a_id = -1;
tgt[t].a_perm = mask;
}
/* Recompute default mask, if requested */
if (recompute_def_mask && need_def_mask && mask_opt >= 0
&& (mask_opt > 0 || !has_def_mask))
{
if (def_mask_idx >= 0)
t = def_mask_idx;
else
t = searchace (tgt, MAX_ACL_ENTRIES, DEF_CLASS_OBJ, -1);
if (t < 0)
return -1;
if (t >= tcnt)
++tcnt;
tgt[t].a_type = DEF_CLASS_OBJ;
tgt[t].a_id = -1;
tgt[t].a_perm = def_mask;
}
return tcnt; return tcnt;
} }
@ -333,7 +425,7 @@ addmissing (aclent_t *tgt, int tcnt)
} }
int int
delacl (aclent_t *tgt, int tcnt, action_t action) delallacl (aclent_t *tgt, int tcnt, action_t action)
{ {
int t; int t;
@ -369,7 +461,7 @@ setfacl (action_t action, const char *path, aclent_t *acls, int cnt)
break; break;
case Delete: case Delete:
if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0 if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0
|| (lcnt = modacl (lacl, lcnt, acls, cnt)) < 0 || (lcnt = delacl (lacl, lcnt, acls, cnt)) < 0
|| (lcnt = acl (path, SETACL, lcnt, lacl)) < 0) || (lcnt = acl (path, SETACL, lcnt, lacl)) < 0)
{ {
perror (prog_name); perror (prog_name);
@ -379,7 +471,7 @@ setfacl (action_t action, const char *path, aclent_t *acls, int cnt)
case DeleteAll: case DeleteAll:
case DeleteDef: case DeleteDef:
if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0 if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0
|| (lcnt = delacl (lacl, lcnt, action)) < 0 || (lcnt = delallacl (lacl, lcnt, action)) < 0
|| (lcnt = acl (path, SETACL, lcnt, lacl)) < 0) || (lcnt = acl (path, SETACL, lcnt, lacl)) < 0)
{ {
perror (prog_name); perror (prog_name);
@ -404,26 +496,24 @@ static void
usage (FILE *stream) usage (FILE *stream)
{ {
fprintf (stream, "" fprintf (stream, ""
"Usage: %s [-r] {-f ACL_FILE | -s acl_entries} FILE...\n" "Usage: %s {-f ACL_FILE | -s acl_entries} FILE...\n"
" %s [-r] {-b|[-d acl_entries] [-m acl_entries]} FILE...\n" " %s {-b|[-x acl_entries] [-m acl_entries]} FILE...\n"
"\n" "\n"
"Modify file and directory access control lists (ACLs)\n" "Modify file and directory access control lists (ACLs)\n"
"\n" "\n"
" -b, --remove-all remove all extended ACL entries\n" " -b, --remove-all remove all extended ACL entries\n"
" -d, --delete delete one or more specified ACL entries\n" " -x, --delete delete one or more specified ACL entries\n"
" -f, --file set ACL entries for FILE to ACL entries read\n" " -f, --file set ACL entries for FILE to ACL entries read\n"
" from a ACL_FILE\n" " from ACL_FILE\n"
" -k, --remove-default\n" " -k, --remove-default remove all default ACL entries\n"
" remove all default ACL entries\n"
" -m, --modify modify one or more specified ACL entries\n" " -m, --modify modify one or more specified ACL entries\n"
" -r, --replace replace mask entry with maximum permissions\n" " -n, --no-mask don't recalculate the effective rights mask\n"
" needed for the file group class\n" " --mask do recalculate the effective rights mask\n"
" -s, --substitute substitute specified ACL entries for the\n" " -s, --substitute substitute specified ACL entries on FILE\n"
" ACL of FILE\n" " -V, --version print version and exit\n"
" -h, --help output usage information and exit\n" " -h, --help this help text\n"
" -V, --version output version information and exit\n"
"\n" "\n"
"At least one of (-b, -d, -f, -k, -m, -s) must be specified\n" "At least one of (-b, -x, -f, -k, -m, -s) must be specified\n"
"\n", prog_name, prog_name); "\n", prog_name, prog_name);
if (stream == stdout) if (stream == stdout)
{ {
@ -457,10 +547,12 @@ usage (FILE *stream)
"\n" "\n"
"The following options are supported:\n" "The following options are supported:\n"
"\n" "\n"
"-b Remove all extended ACL entries. The base ACL entries of the\n" "-b, --remove-all\n"
" Remove all extended ACL entries. The base ACL entries of the\n"
" owner, group and others are retained.\n" " owner, group and others are retained.\n"
"\n" "\n"
"-d Delete one or more specified entries from the file's ACL.\n" "-x, --delete\n"
" Delete one or more specified entries from the file's ACL.\n"
" The owner, group and others entries must not be deleted.\n" " The owner, group and others entries must not be deleted.\n"
" Acl_entries to be deleted should be specified without\n" " Acl_entries to be deleted should be specified without\n"
" permissions, as in the following list:\n" " permissions, as in the following list:\n"
@ -473,7 +565,8 @@ usage (FILE *stream)
" d[efault]:m[ask][:]\n" " d[efault]:m[ask][:]\n"
" d[efault]:o[ther][:]\n" " d[efault]:o[ther][:]\n"
"\n" "\n"
"-f Take the Acl_entries from ACL_FILE one per line. Whitespace\n" "-f, --file\n"
" Take the Acl_entries from ACL_FILE one per line. Whitespace\n"
" characters are ignored, and the character \"#\" may be used\n" " characters are ignored, and the character \"#\" may be used\n"
" to start a comment. The special filename \"-\" indicates\n" " to start a comment. The special filename \"-\" indicates\n"
" reading from stdin.\n" " reading from stdin.\n"
@ -490,21 +583,32 @@ usage (FILE *stream)
" - One default mask entry for the file group class.\n" " - One default mask entry for the file group class.\n"
" - One default other entry.\n" " - One default other entry.\n"
"\n" "\n"
"-k Remove all default ACL entries. If no default ACL entries\n" "-k, --remove-default\n"
" exist, no warnings are issued.\n" " Remove all default ACL entries. If no default ACL entries exist,\n"
" no warnings are issued.\n"
"\n" "\n"
"-m Add or modify one or more specified ACL entries.\n" "-m, --modify\n"
" Acl_entries is a comma-separated list of entries from the \n" " Add or modify one or more specified ACL entries. Acl_entries is\n"
" same list as above.\n" " a comma-separated list of entries from the same list as above.\n"
"\n" "\n"
"-r Causes the permissions specified in the mask entry to be\n" "-n, --no-mask\n"
" ignored and replaced by the maximum permissions needed for\n" " Valid in conjunction with -m. Do not recalculate the effective\n"
" the file group class.\n" " rights mask. The default behavior of setfacl is to recalculate the\n"
" ACL mask entry, unless a mask entry was explicitly given. The\n"
" mask entry is set to the union of all permissions of the owning\n"
" group, and all named user and group entries. (These are exactly\n"
" the entries affected by the mask entry).\n"
"\n" "\n"
"-s Like -f, but substitute the file's ACL with Acl_entries\n" "--mask\n"
" Valid in conjunction with -m. Do recalculate the effective rights\n"
" mask, even if an ACL mask entry was explicitly given. (See the\n"
" -n option.)\n"
"\n"
"-s, --substitute\n"
" Like -f, but substitute the file's ACL with ACL entries\n"
" specified in a comma-separated list on the command line.\n" " specified in a comma-separated list on the command line.\n"
"\n" "\n"
"While the -d and -m options may be used in the same command, the\n" "While the -x and -m options may be used in the same command, the\n"
"-f and -s options may be used only exclusively.\n" "-f and -s options may be used only exclusively.\n"
"\n" "\n"
"Directories may contain default ACL entries. Files created\n" "Directories may contain default ACL entries. Files created\n"
@ -519,17 +623,19 @@ usage (FILE *stream)
struct option longopts[] = { struct option longopts[] = {
{"remove-all", no_argument, NULL, 'b'}, {"remove-all", no_argument, NULL, 'b'},
{"delete", required_argument, NULL, 'd'}, {"delete", required_argument, NULL, 'x'},
{"file", required_argument, NULL, 'f'}, {"file", required_argument, NULL, 'f'},
{"remove-default", no_argument, NULL, 'k'}, {"remove-default", no_argument, NULL, 'k'},
{"modify", required_argument, NULL, 'm'}, {"modify", required_argument, NULL, 'm'},
{"no-mask", required_argument, NULL, 'n'},
{"mask", required_argument, NULL, '\n'},
{"replace", no_argument, NULL, 'r'}, {"replace", no_argument, NULL, 'r'},
{"substitute", required_argument, NULL, 's'}, {"substitute", required_argument, NULL, 's'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'}, {"version", no_argument, NULL, 'V'},
{0, no_argument, NULL, 0} {0, no_argument, NULL, 0}
}; };
const char *opts = "bd:f:hkm:rs:V"; const char *opts = "bd:f:hkm:nrs:Vx";
static void static void
print_version () print_version ()
@ -550,7 +656,6 @@ main (int argc, char **argv)
{ {
int c; int c;
action_t action = NoAction; action_t action = NoAction;
int ropt = 0;
aclent_t acls[MAX_ACL_ENTRIES]; aclent_t acls[MAX_ACL_ENTRIES];
int aclidx = 0; int aclidx = 0;
int ret = 0; int ret = 0;
@ -570,7 +675,8 @@ main (int argc, char **argv)
return 1; return 1;
} }
break; break;
case 'd': case 'd': /* Backward compat */
case 'x':
if (action == NoAction) if (action == NoAction)
action = Delete; action = Delete;
else if (action == Modify) else if (action == Modify)
@ -628,14 +734,13 @@ main (int argc, char **argv)
return 2; return 2;
} }
break; break;
case 'n':
mask_opt = -1;
break;
case '\n':
mask_opt = 1;
break;
case 'r': case 'r':
if (!ropt)
ropt = 1;
else
{
usage (stderr);
return 1;
}
break; break;
case 's': case 's':
if (action == NoAction) if (action == NoAction)