>From 9186e94b12b5b9a4fde37cb54328259788c78b94 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Mon, 22 Jun 2009 22:24:56 -0700 Subject: [PATCH] Include the S_ISUID, S_ISGID, S_ISVTX flags in the getfacl output, and restore them with "setfacl --restore=file". --- getfacl/getfacl.c | 14 ++++++++++++ setfacl/Makefile | 2 +- setfacl/do_set.c | 21 ++++++++++-------- setfacl/parse.c | 28 ++++++++++++++++++++++++- setfacl/parse.h | 3 +- setfacl/setfacl.c | 53 +++++++++++++++++++++++++++++++--------------- test/sbits-restore.test | 22 +++++++++++++++++++ 7 files changed, 114 insertions(+), 29 deletions(-) create mode 100644 test/sbits-restore.test diff --git a/getfacl/getfacl.c b/getfacl/getfacl.c index fc650e3..e267414 100644 --- a/getfacl/getfacl.c +++ b/getfacl/getfacl.c @@ -423,6 +423,18 @@ acl_get_file_mode(const char *path_p) return acl_from_mode(st.st_mode); } +static const char * +flagstr(mode_t mode) +{ + static char str[4]; + + str[0] = (mode & S_ISUID) ? 's' : '-'; + str[1] = (mode & S_ISGID) ? 's' : '-'; + str[2] = (mode & S_ISVTX) ? 't' : '-'; + str[3] = '\0'; + return str; +} + int do_print(const char *path_p, const struct stat *st, int walk_flags, void *unused) { const char *default_prefix = NULL; @@ -498,6 +510,8 @@ int do_print(const char *path_p, const struct stat *st, int walk_flags, void *un xquote(user_name(st->st_uid, opt_numeric), " \t\n\r")); printf("# group: %s\n", xquote(group_name(st->st_gid, opt_numeric), " \t\n\r")); + if (st->st_mode & (S_ISVTX | S_ISUID | S_ISGID)) + printf("# flags: %s\n", flagstr(st->st_mode)); } if (acl != NULL) { char *acl_text = acl_to_any_text(acl, NULL, '\n', diff --git a/setfacl/Makefile b/setfacl/Makefile index 46b74d9..c44e7c0 100644 --- a/setfacl/Makefile +++ b/setfacl/Makefile @@ -21,7 +21,7 @@ include $(TOPDIR)/include/builddefs LTCOMMAND = setfacl CFILES = setfacl.c do_set.c sequence.c parse.c -HFILES = sequence.h parse.h +HFILES = sequence.h parse.h do_set.h LLDLIBS = $(LIBMISC) $(LIBACL) $(LIBATTR) LTDEPENDENCIES = $(LIBMISC) $(LIBACL) diff --git a/setfacl/do_set.c b/setfacl/do_set.c index b9c0ce7..3e7e982 100644 --- a/setfacl/do_set.c +++ b/setfacl/do_set.c @@ -34,6 +34,7 @@ #include #include #include "sequence.h" +#include "do_set.h" #include "parse.h" #include "config.h" #include "walk_tree.h" @@ -262,7 +263,7 @@ do_set( int walk_flags, void *arg) { - const seq_t seq = (const seq_t)arg; + struct do_set_args *args = arg; acl_t old_acl = NULL, old_default_acl = NULL; acl_t acl = NULL, default_acl = NULL; acl_t *xacl, *old_xacl; @@ -290,7 +291,7 @@ do_set( return 0; /* Execute the commands in seq (read ACLs on demand) */ - error = seq_get_cmd(seq, SEQ_FIRST_CMD, &cmd); + error = seq_get_cmd(args->seq, SEQ_FIRST_CMD, &cmd); if (error == 0) return 0; while (error == 1) { @@ -357,7 +358,7 @@ do_set( goto fail; } - error = seq_get_cmd(seq, SEQ_NEXT_CMD, &cmd); + error = seq_get_cmd(args->seq, SEQ_NEXT_CMD, &cmd); } if (error < 0) @@ -467,19 +468,21 @@ do_set( goto cleanup; } if (acl) { + int equiv_mode; + mode_t mode = 0; + + equiv_mode = acl_equiv_mode(acl, &mode); + if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) != 0) { if (errno == ENOSYS || errno == ENOTSUP) { - int saved_errno = errno; - mode_t mode; - - if (acl_equiv_mode(acl, &mode) != 0) { - errno = saved_errno; + if (equiv_mode != 0) goto fail; - } else if (chmod(path_p, mode) != 0) + else if (chmod(path_p, mode) != 0) goto fail; } else goto fail; } + args->mode = mode; } if (default_acl) { if (S_ISDIR(st->st_mode)) { diff --git a/setfacl/parse.c b/setfacl/parse.c index daa32e2..4df1a19 100644 --- a/setfacl/parse.c +++ b/setfacl/parse.c @@ -410,7 +410,8 @@ read_acl_comments( int *line, char **path_p, uid_t *uid_p, - gid_t *gid_p) + gid_t *gid_p, + mode_t *flags) { int c; /* @@ -429,6 +430,8 @@ read_acl_comments( *uid_p = ACL_UNDEFINED_ID; if (gid_p) *gid_p = ACL_UNDEFINED_ID; + if (flags) + *flags = 0; for(;;) { c = fgetc(file); @@ -493,6 +496,29 @@ read_acl_comments( if (get_gid(unquote(cp), gid_p) != 0) continue; } + } else if (strncmp(cp, "flags:", 6) == 0) { + mode_t f = 0; + + cp += 6; + SKIP_WS(cp); + + if (cp[0] == 's') + f |= S_ISUID; + else if (cp[0] != '-') + goto fail; + if (cp[1] == 's') + f |= S_ISGID; + else if (cp[1] != '-') + goto fail; + if (cp[2] == 't') + f |= S_ISVTX; + else if (cp[2] != '-') + goto fail; + if (cp[3] != '\0') + goto fail; + + if (flags) + *flags = f; } } if (ferror(file)) diff --git a/setfacl/parse.h b/setfacl/parse.h index b6b7e01..b2e68b4 100644 --- a/setfacl/parse.h +++ b/setfacl/parse.h @@ -64,7 +64,8 @@ read_acl_comments( int *line, char **path_p, uid_t *uid_p, - gid_t *gid_p); + gid_t *gid_p, + mode_t *flags); int read_acl_seq( FILE *file, diff --git a/setfacl/setfacl.c b/setfacl/setfacl.c index a4ce899..091b9cc 100644 --- a/setfacl/setfacl.c +++ b/setfacl/setfacl.c @@ -33,11 +33,10 @@ #include "config.h" #include "sequence.h" #include "parse.h" +#include "do_set.h" #include "walk_tree.h" #include "misc.h" -extern int do_set(const char *path_p, const struct stat *stat_p, int flags, void *arg); - #define POSIXLY_CORRECT_STR "POSIXLY_CORRECT" /* '-' stands for `process non-option arguments in loop' */ @@ -125,7 +124,8 @@ restore( struct stat st; uid_t uid; gid_t gid; - seq_t seq = NULL; + mode_t mask, flags; + struct do_set_args args; int line = 0, backup_line; int error, status = 0; @@ -133,7 +133,8 @@ restore( for(;;) { backup_line = line; - error = read_acl_comments(file, &line, &path_p, &uid, &gid); + error = read_acl_comments(file, &line, &path_p, &uid, &gid, + &flags); if (error < 0) goto fail; if (error == 0) @@ -155,13 +156,13 @@ restore( goto getout; } - if (!(seq = seq_init())) + if (!(args.seq = seq_init())) goto fail; - if (seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_ACCESS) || - seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_DEFAULT)) + if (seq_append_cmd(args.seq, CMD_REMOVE_ACL, ACL_TYPE_ACCESS) || + seq_append_cmd(args.seq, CMD_REMOVE_ACL, ACL_TYPE_DEFAULT)) goto fail; - error = read_acl_seq(file, seq, CMD_ENTRY_REPLACE, + error = read_acl_seq(file, args.seq, CMD_ENTRY_REPLACE, SEQ_PARSE_WITH_PERM | SEQ_PARSE_DEFAULT | SEQ_PARSE_MULTI, @@ -181,7 +182,8 @@ restore( status = 1; } - error = do_set(path_p, &st, 0, seq); + args.mode = 0; + error = do_set(path_p, &st, 0, &args); if (error != 0) { status = 1; goto resume; @@ -205,14 +207,28 @@ restore( status = 1; } } + + mask = S_ISUID | S_ISGID | S_ISVTX; + if ((st.st_mode & mask) != (flags & mask)) { + if (!args.mode) + args.mode = st.st_mode; + args.mode &= (S_IRWXU | S_IRWXG | S_IRWXO); + if (chmod(path_p, flags | args.mode) != 0) { + fprintf(stderr, _("%s: %s: Cannot change " + "mode: %s\n"), + progname, xquote(path_p, "\n\r"), + strerror(errno)); + status = 1; + } + } resume: if (path_p) { free(path_p); path_p = NULL; } - if (seq) { - seq_free(seq); - seq = NULL; + if (args.seq) { + seq_free(args.seq); + args.seq = NULL; } } @@ -221,9 +237,9 @@ getout: free(path_p); path_p = NULL; } - if (seq) { - seq_free(seq); - seq = NULL; + if (args.seq) { + seq_free(args.seq); + args.seq = NULL; } return status; @@ -280,17 +296,20 @@ int next_file(const char *arg, seq_t seq) { char *line; int errors = 0; + struct do_set_args args; + + args.seq = seq; if (strcmp(arg, "-") == 0) { while ((line = next_line(stdin))) - errors = walk_tree(line, walk_flags, 0, do_set, seq); + errors = walk_tree(line, walk_flags, 0, do_set, &args); if (!feof(stdin)) { fprintf(stderr, _("%s: Standard input: %s\n"), progname, strerror(errno)); errors = 1; } } else { - errors = walk_tree(arg, walk_flags, 0, do_set, seq); + errors = walk_tree(arg, walk_flags, 0, do_set, &args); } return errors ? 1 : 0; } diff --git a/test/sbits-restore.test b/test/sbits-restore.test new file mode 100644 index 0000000..e5e4fb2 --- /dev/null +++ b/test/sbits-restore.test @@ -0,0 +1,22 @@ +Ensure setting of SUID/SGID/sticky via --restore works + + $ umask 022 + $ mkdir d + $ touch d/g + $ touch d/u + $ chmod u+s d/u + $ chmod g+s d/g + $ chmod +t d + $ getfacl -R d > d.acl + $ rm -R d + $ mkdir d + $ touch d/g + $ touch d/u + $ setfacl --restore d.acl + $ ls -dl d | awk '{print $1}' + > drwxr-xr-t + $ ls -dl d/u | awk '{print $1}' + > -rwSr--r-- + $ ls -dl d/g | awk '{print $1}' + > -rw-r-Sr-- + $ rm -Rf d -- 1.6.2