Changeset View
Changeset View
Standalone View
Standalone View
head/bin/setfacl/setfacl.c
Show All 21 Lines | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * 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 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/stat.h> | |||||
#include <sys/acl.h> | #include <sys/acl.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fts.h> | #include <fts.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
Show All 27 Lines | |||||
static bool h_flag; | static bool h_flag; | ||||
static bool H_flag; | static bool H_flag; | ||||
static bool L_flag; | static bool L_flag; | ||||
static bool R_flag; | static bool R_flag; | ||||
static bool need_mask; | static bool need_mask; | ||||
static acl_type_t acl_type = ACL_TYPE_ACCESS; | static acl_type_t acl_type = ACL_TYPE_ACCESS; | ||||
static int handle_file(FTS *ftsp, FTSENT *file); | static int handle_file(FTS *ftsp, FTSENT *file); | ||||
static acl_t clear_inheritance_flags(acl_t acl); | |||||
static char **stdin_files(void); | static char **stdin_files(void); | ||||
static void usage(void); | static void usage(void); | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
fprintf(stderr, "usage: setfacl [-R [-H | -L | -P]] [-bdhkn] " | fprintf(stderr, "usage: setfacl [-R [-H | -L | -P]] [-bdhkn] " | ||||
Show All 35 Lines | stdin_files(void) | ||||
} | } | ||||
/* fts_open() requires the last array element to be NULL. */ | /* fts_open() requires the last array element to be NULL. */ | ||||
files_list[i] = NULL; | files_list[i] = NULL; | ||||
return (files_list); | return (files_list); | ||||
} | } | ||||
/* | |||||
* Remove any inheritance flags from NFSv4 ACLs when running in recursive | |||||
* mode. This is to avoid files being assigned identical ACLs to their | |||||
* parent directory while also being set to inherit them. | |||||
* | |||||
* The acl argument is assumed to be valid. | |||||
*/ | |||||
static acl_t | |||||
clear_inheritance_flags(acl_t acl) | |||||
{ | |||||
acl_t nacl; | |||||
acl_entry_t acl_entry; | |||||
acl_flagset_t acl_flagset; | |||||
int acl_brand, entry_id; | |||||
(void)acl_get_brand_np(acl, &acl_brand); | |||||
if (acl_brand != ACL_BRAND_NFS4) | |||||
return (acl); | |||||
nacl = acl_dup(acl); | |||||
if (nacl == NULL) { | |||||
warn("acl_dup() failed"); | |||||
return (acl); | |||||
} | |||||
entry_id = ACL_FIRST_ENTRY; | |||||
while (acl_get_entry(nacl, entry_id, &acl_entry) == 1) { | |||||
entry_id = ACL_NEXT_ENTRY; | |||||
if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { | |||||
warn("acl_get_flagset_np() failed"); | |||||
continue; | |||||
} | |||||
if (acl_get_flag_np(acl_flagset, ACL_ENTRY_INHERIT_ONLY) == 1) { | |||||
if (acl_delete_entry(nacl, acl_entry) != 0) | |||||
warn("acl_delete_entry() failed"); | |||||
continue; | |||||
} | |||||
if (acl_delete_flag_np(acl_flagset, | |||||
ACL_ENTRY_FILE_INHERIT | | |||||
ACL_ENTRY_DIRECTORY_INHERIT | | |||||
ACL_ENTRY_NO_PROPAGATE_INHERIT) != 0) | |||||
warn("acl_delete_flag_np() failed"); | |||||
} | |||||
return (nacl); | |||||
} | |||||
static int | static int | ||||
handle_file(FTS *ftsp, FTSENT *file) | handle_file(FTS *ftsp, FTSENT *file) | ||||
{ | { | ||||
acl_t acl; | acl_t acl, nacl; | ||||
acl_entry_t unused_entry; | acl_entry_t unused_entry; | ||||
int local_error, ret; | int local_error, ret; | ||||
struct sf_entry *entry; | struct sf_entry *entry; | ||||
bool follow_symlink; | bool follow_symlink; | ||||
local_error = 0; | local_error = 0; | ||||
switch (file->fts_info) { | switch (file->fts_info) { | ||||
case FTS_D: | case FTS_D: | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (follow_symlink) | ||||
warn("%s: acl_get_file() failed", file->fts_path); | warn("%s: acl_get_file() failed", file->fts_path); | ||||
else | else | ||||
warn("%s: acl_get_link_np() failed", file->fts_path); | warn("%s: acl_get_link_np() failed", file->fts_path); | ||||
return (1); | return (1); | ||||
} | } | ||||
/* Cycle through each option. */ | /* Cycle through each option. */ | ||||
TAILQ_FOREACH(entry, &entrylist, next) { | TAILQ_FOREACH(entry, &entrylist, next) { | ||||
if (local_error) | nacl = entry->acl; | ||||
continue; | |||||
switch(entry->op) { | switch (entry->op) { | ||||
case OP_ADD_ACL: | case OP_ADD_ACL: | ||||
local_error += add_acl(entry->acl, entry->entry_number, | if (R_flag && file->fts_info != FTS_D && | ||||
&acl, file->fts_path); | acl_type == ACL_TYPE_NFS4) | ||||
nacl = clear_inheritance_flags(nacl); | |||||
local_error += add_acl(nacl, entry->entry_number, &acl, | |||||
file->fts_path); | |||||
break; | break; | ||||
case OP_MERGE_ACL: | case OP_MERGE_ACL: | ||||
local_error += merge_acl(entry->acl, &acl, | if (R_flag && file->fts_info != FTS_D && | ||||
file->fts_path); | acl_type == ACL_TYPE_NFS4) | ||||
nacl = clear_inheritance_flags(nacl); | |||||
local_error += merge_acl(nacl, &acl, file->fts_path); | |||||
need_mask = true; | need_mask = true; | ||||
break; | break; | ||||
case OP_REMOVE_EXT: | case OP_REMOVE_EXT: | ||||
/* | /* | ||||
* Don't try to call remove_ext() for empty | * Don't try to call remove_ext() for empty | ||||
* default ACL. | * default ACL. | ||||
*/ | */ | ||||
if (acl_type == ACL_TYPE_DEFAULT && | if (acl_type == ACL_TYPE_DEFAULT && | ||||
Show All 20 Lines | case OP_REMOVE_DEF: | ||||
local_error++; | local_error++; | ||||
} | } | ||||
if (acl_type == ACL_TYPE_DEFAULT) | if (acl_type == ACL_TYPE_DEFAULT) | ||||
local_error += remove_default(&acl, | local_error += remove_default(&acl, | ||||
file->fts_path); | file->fts_path); | ||||
need_mask = false; | need_mask = false; | ||||
break; | break; | ||||
case OP_REMOVE_ACL: | case OP_REMOVE_ACL: | ||||
local_error += remove_acl(entry->acl, &acl, | local_error += remove_acl(nacl, &acl, file->fts_path); | ||||
file->fts_path); | |||||
need_mask = true; | need_mask = true; | ||||
break; | break; | ||||
case OP_REMOVE_BY_NUMBER: | case OP_REMOVE_BY_NUMBER: | ||||
local_error += remove_by_number(entry->entry_number, | local_error += remove_by_number(entry->entry_number, | ||||
&acl, file->fts_path); | &acl, file->fts_path); | ||||
need_mask = true; | need_mask = true; | ||||
break; | break; | ||||
} | } | ||||
if (nacl != entry->acl) { | |||||
acl_free(nacl); | |||||
nacl = NULL; | |||||
} | |||||
if (local_error) | |||||
break; | |||||
} | } | ||||
ret = 0; | ret = 0; | ||||
/* | /* | ||||
* Don't try to set an empty default ACL; it will always fail. | * Don't try to set an empty default ACL; it will always fail. | ||||
* Use acl_delete_def_file(3) instead. | * Use acl_delete_def_file(3) instead. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 190 Lines • Show Last 20 Lines |