Changeset View
Changeset View
Standalone View
Standalone View
bin/setfacl/setfacl.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
/* file operations */ | /* file operations */ | ||||
#define OP_MERGE_ACL 0x00 /* merge acl's (-mM) */ | #define OP_MERGE_ACL 0x00 /* merge acl's (-mM) */ | ||||
#define OP_REMOVE_DEF 0x01 /* remove default acl's (-k) */ | #define OP_REMOVE_DEF 0x01 /* remove default acl's (-k) */ | ||||
#define OP_REMOVE_EXT 0x02 /* remove extended acl's (-b) */ | #define OP_REMOVE_EXT 0x02 /* remove extended acl's (-b) */ | ||||
#define OP_REMOVE_ACL 0x03 /* remove acl's (-xX) */ | #define OP_REMOVE_ACL 0x03 /* remove acl's (-xX) */ | ||||
#define OP_REMOVE_BY_NUMBER 0x04 /* remove acl's (-xX) by acl entry number */ | #define OP_REMOVE_BY_NUMBER 0x04 /* remove acl's (-xX) by acl entry number */ | ||||
#define OP_ADD_ACL 0x05 /* add acls entries at a given position */ | #define OP_ADD_ACL 0x05 /* add acls entries at a given position */ | ||||
#define OP_SET_FLAG 0x06 /* set the ACL flag - V4 only*/ | |||||
#define OP_AI_PROPAGATE 0x07 /* propagate ACL based on auto-inheritence rules - V4 only*/ | |||||
/* TAILQ entry for acl operations */ | /* TAILQ entry for acl operations */ | ||||
struct sf_entry { | struct sf_entry { | ||||
uint op; | uint op; | ||||
acl_t acl; | acl_t acl; | ||||
uint entry_number; | uint entry_number; | ||||
TAILQ_ENTRY(sf_entry) next; | TAILQ_ENTRY(sf_entry) next; | ||||
}; | }; | ||||
static TAILQ_HEAD(, sf_entry) entrylist; | static TAILQ_HEAD(, sf_entry) entrylist; | ||||
bool have_mask; | bool have_mask; | ||||
bool have_stdin; | bool have_stdin; | ||||
bool n_flag; | bool n_flag; | ||||
bool f_flag; | |||||
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 acl_aclflag_t acl_flag = 0; | |||||
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 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]] [-bdfhkn] " | ||||
"[-a position entries] [-m entries] [-M file] " | "[-a position entries] [-m entries] [-M file] [-i flag] " | ||||
"[-x entries] [-X file] [file ...]\n"); | "[-x entries] [-X file] [file ...]\n"); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
static const struct { | |||||
acl_aclflag_t flag; | |||||
const char *flagstr; | |||||
} acl_flag_str[] = { | |||||
{ ACL_ACLFLAG_AUTO_INHERIT, "auto-inherit" }, | |||||
{ ACL_ACLFLAG_PROTECTED, "protected" }, | |||||
{ ACL_ACLFLAG_DEFAULTED, "defaulted" }, | |||||
{ 0, "none" }, | |||||
}; | |||||
static char ** | static char ** | ||||
stdin_files(void) | stdin_files(void) | ||||
{ | { | ||||
char **files_list; | char **files_list; | ||||
char filename[PATH_MAX]; | char filename[PATH_MAX]; | ||||
size_t fl_count, i; | size_t fl_count, i; | ||||
if (have_stdin) | if (have_stdin) | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | case OP_REMOVE_ACL: | ||||
local_error += remove_acl(nacl, &acl, file->fts_path); | local_error += remove_acl(nacl, &acl, 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; | ||||
case OP_SET_FLAG: | |||||
local_error += set_aclflag(acl, acl_flag); | |||||
break; | |||||
case OP_AI_PROPAGATE: | |||||
/* | |||||
* No changes made at root level and branches with | |||||
* PROTECTED set are pruned. | |||||
*/ | |||||
if (file->fts_level == FTS_ROOTLEVEL) { | |||||
acl_free(acl); | |||||
return (0); | |||||
} | } | ||||
local_error += acl_get_aclflag_np(acl, &acl_flag); | |||||
if (acl_flag == ACL_ACLFLAG_PROTECTED) { | |||||
fts_set(ftsp, file, FTS_SKIP); | |||||
acl_free(acl); | |||||
return (0); | |||||
} | |||||
local_error += auto_inherit_propagate(&acl, file); | |||||
break; | |||||
} | |||||
if (nacl != entry->acl) { | if (nacl != entry->acl) { | ||||
acl_free(nacl); | acl_free(nacl); | ||||
nacl = NULL; | nacl = NULL; | ||||
} | } | ||||
if (local_error) | if (local_error) | ||||
break; | break; | ||||
} | } | ||||
Show All 37 Lines | out: | ||||
acl_free(acl); | acl_free(acl); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
int carried_error, ch, entry_number, fts_options; | int carried_error, ch, entry_number, fts_options; | ||||
uint i; | |||||
bool flag_is_valid, ok, has_autoinherit; | |||||
FTS *ftsp; | FTS *ftsp; | ||||
FTSENT *file; | FTSENT *file; | ||||
char **files_list; | char **files_list; | ||||
struct sf_entry *entry; | struct sf_entry *entry; | ||||
char *end; | char *end; | ||||
acl_type = ACL_TYPE_ACCESS; | acl_type = ACL_TYPE_ACCESS; | ||||
carried_error = fts_options = 0; | carried_error = fts_options = 0; | ||||
have_mask = have_stdin = n_flag = false; | have_mask = have_stdin = f_flag = n_flag = false; | ||||
ok = flag_is_valid = has_autoinherit = false; | |||||
TAILQ_INIT(&entrylist); | TAILQ_INIT(&entrylist); | ||||
while ((ch = getopt(argc, argv, "HLM:PRX:a:bdhkm:nx:")) != -1) | while ((ch = getopt(argc, argv, "HLM:PRX:a:fi:bdhkpm:nx:")) != -1) | ||||
switch(ch) { | switch(ch) { | ||||
case 'H': | case 'H': | ||||
H_flag = true; | H_flag = true; | ||||
L_flag = false; | L_flag = false; | ||||
break; | break; | ||||
case 'L': | case 'L': | ||||
L_flag = true; | L_flag = true; | ||||
H_flag = false; | H_flag = false; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | while ((ch = getopt(argc, argv, "HLM:PRX:a:fi:bdhkpm:nx:")) != -1) | ||||
case 'b': | case 'b': | ||||
entry = zmalloc(sizeof(struct sf_entry)); | entry = zmalloc(sizeof(struct sf_entry)); | ||||
entry->op = OP_REMOVE_EXT; | entry->op = OP_REMOVE_EXT; | ||||
TAILQ_INSERT_TAIL(&entrylist, entry, next); | TAILQ_INSERT_TAIL(&entrylist, entry, next); | ||||
break; | break; | ||||
case 'd': | case 'd': | ||||
acl_type = ACL_TYPE_DEFAULT; | acl_type = ACL_TYPE_DEFAULT; | ||||
break; | break; | ||||
case 'f': | |||||
f_flag = true; | |||||
break; | |||||
case 'h': | case 'h': | ||||
h_flag = 1; | h_flag = 1; | ||||
break; | break; | ||||
case 'i': | |||||
entry = zmalloc(sizeof(struct sf_entry)); | |||||
for (i = 0; i < ARRAY_SIZE(acl_flag_str); i++) { | |||||
if (strcmp(optarg, acl_flag_str[i].flagstr) == 0) { | |||||
acl_flag = acl_flag_str[i].flag; | |||||
flag_is_valid = true; | |||||
break; | |||||
} | |||||
} | |||||
if (!flag_is_valid) { | |||||
errno = EINVAL; | |||||
err(1, "%s is not a valid ACL flag. " | |||||
"Supported flags are: auto-inherit, " | |||||
"protected, defaulted, and none.", optarg); | |||||
} | |||||
entry->op = OP_SET_FLAG; | |||||
TAILQ_INSERT_TAIL(&entrylist, entry, next); | |||||
break; | |||||
case 'k': | case 'k': | ||||
entry = zmalloc(sizeof(struct sf_entry)); | entry = zmalloc(sizeof(struct sf_entry)); | ||||
entry->op = OP_REMOVE_DEF; | entry->op = OP_REMOVE_DEF; | ||||
TAILQ_INSERT_TAIL(&entrylist, entry, next); | TAILQ_INSERT_TAIL(&entrylist, entry, next); | ||||
break; | break; | ||||
case 'm': | case 'm': | ||||
entry = zmalloc(sizeof(struct sf_entry)); | entry = zmalloc(sizeof(struct sf_entry)); | ||||
entry->acl = acl_from_text(optarg); | entry->acl = acl_from_text(optarg); | ||||
if (entry->acl == NULL) | if (entry->acl == NULL) | ||||
err(1, "%s", optarg); | err(1, "%s", optarg); | ||||
entry->op = OP_MERGE_ACL; | entry->op = OP_MERGE_ACL; | ||||
TAILQ_INSERT_TAIL(&entrylist, entry, next); | TAILQ_INSERT_TAIL(&entrylist, entry, next); | ||||
break; | break; | ||||
case 'n': | case 'n': | ||||
n_flag = true; | n_flag = true; | ||||
break; | break; | ||||
case 'p': | |||||
entry = zmalloc(sizeof(struct sf_entry)); | |||||
entry->op = OP_AI_PROPAGATE; | |||||
TAILQ_INSERT_TAIL(&entrylist, entry, next); | |||||
has_autoinherit = true; | |||||
break; | |||||
case 'x': | case 'x': | ||||
entry = zmalloc(sizeof(struct sf_entry)); | entry = zmalloc(sizeof(struct sf_entry)); | ||||
entry_number = strtol(optarg, &end, 10); | entry_number = strtol(optarg, &end, 10); | ||||
if (end - optarg == (int)strlen(optarg)) { | if (end - optarg == (int)strlen(optarg)) { | ||||
if (entry_number < 0) | if (entry_number < 0) | ||||
errx(1, | errx(1, | ||||
"%s: entry number cannot be less than zero", | "%s: entry number cannot be less than zero", | ||||
optarg); | optarg); | ||||
Show All 17 Lines | main(int argc, char *argv[]) | ||||
if (!n_flag && TAILQ_EMPTY(&entrylist)) | if (!n_flag && TAILQ_EMPTY(&entrylist)) | ||||
usage(); | usage(); | ||||
/* Take list of files from stdin. */ | /* Take list of files from stdin. */ | ||||
if (argc == 0 || strcmp(argv[0], "-") == 0) { | if (argc == 0 || strcmp(argv[0], "-") == 0) { | ||||
files_list = stdin_files(); | files_list = stdin_files(); | ||||
} else | } else | ||||
files_list = argv; | files_list = argv; | ||||
if (has_autoinherit) { | |||||
ok = auto_inherit_check(files_list); | |||||
TAILQ_FOREACH(entry, &entrylist, next) { | |||||
if (entry->op != OP_AI_PROPAGATE) { | |||||
errx(1, "mixing auto-inherit with other ACL operations. " | |||||
trasz: Why the full stops? | |||||
"is not permitted."); | |||||
} | |||||
} | |||||
if (!ok) { | |||||
errx(1, "auto-inheritance safety check failed."); | |||||
} | |||||
R_flag = true; | |||||
} | |||||
if (R_flag) { | if (R_flag) { | ||||
if (h_flag) | if (h_flag) | ||||
errx(1, "the -R and -h options may not be " | errx(1, "the -R and -h options may not be " | ||||
"specified together."); | "specified together."); | ||||
if (L_flag) { | if (L_flag) { | ||||
fts_options = FTS_LOGICAL; | fts_options = FTS_LOGICAL; | ||||
} else { | } else { | ||||
Show All 20 Lines |
Why the full stops?