int restore( FILE *file, const char *filename) { char *path_p; struct stat stat; uid_t uid; gid_t gid; seq_t seq = NULL; int line = 0, backup_line; int error, status = 0; memset(&stat, 0, sizeof(stat)); for(;;) { backup_line = line; error = read_acl_comments(file, &line, &path_p, &uid, &gid); if (error < 0) goto fail; if (error == 0) return 0; if (path_p == NULL) { if (filename) { fprintf(stderr, _("%s: %s: No filename found " "in line %d, aborting\n"), progname, xquote(filename), backup_line); } else { fprintf(stderr, _("%s: No filename found in " "line %d of standard input, " "aborting\n"), progname, backup_line); } goto getout; } if (!(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)) goto fail; error = read_acl_seq(file, seq, CMD_ENTRY_REPLACE, SEQ_PARSE_WITH_PERM | SEQ_PARSE_NO_RELATIVE | SEQ_PARSE_DEFAULT | SEQ_PARSE_MULTI, &line, NULL); if (error != 0) { fprintf(stderr, _("%s: %s: %s in line %d\n"), progname, xquote(filename), strerror(errno), line); goto getout; } error = lstat(path_p, &stat); if (opt_test && error != 0) { fprintf(stderr, "%s: %s: %s\n", progname, xquote(path_p), strerror(errno)); status = 1; } stat.st_uid = uid; stat.st_gid = gid; error = do_set(path_p, &stat, seq); if (error != 0) { status = 1; goto resume; } if (!opt_test && (uid != ACL_UNDEFINED_ID || gid != ACL_UNDEFINED_ID)) { if (chown(path_p, uid, gid) != 0) { fprintf(stderr, _("%s: %s: Cannot change " "owner/group: %s\n"), progname, xquote(path_p), strerror(errno)); status = 1; } } resume: if (path_p) { free(path_p); path_p = NULL; } if (seq) { seq_free(seq); seq = NULL; } } getout: if (path_p) { free(path_p); path_p = NULL; } if (seq) { seq_free(seq); seq = NULL; } return status; fail: fprintf(stderr, "%s: %s: %s\n", progname, xquote(filename), strerror(errno)); status = 1; goto getout; }
int main(int argc, char *argv[]) { int opt; int saw_files = 0; int status = 0; FILE *file; int which; int lineno; int error; seq_t seq = NULL; int seq_cmd, parse_mode; progname = basename(argv[0]); #if POSIXLY_CORRECT cmd_line_options = POSIXLY_CMD_LINE_OPTIONS; cmd_line_spec = _(POSIXLY_CMD_LINE_SPEC); #else if (getenv(POSIXLY_CORRECT_STR)) posixly_correct = 1; if (!posixly_correct) { cmd_line_options = CMD_LINE_OPTIONS; cmd_line_spec = _(CMD_LINE_SPEC); } else { cmd_line_options = POSIXLY_CMD_LINE_OPTIONS; cmd_line_spec = _(POSIXLY_CMD_LINE_SPEC); } #endif setlocale(LC_CTYPE, ""); setlocale(LC_MESSAGES, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); while ((opt = getopt_long(argc, argv, cmd_line_options, long_options, NULL)) != -1) { /* we remember the two REMOVE_ACL commands of the set operations because we may later need to delete them. */ cmd_t seq_remove_default_acl_cmd = NULL; cmd_t seq_remove_acl_cmd = NULL; if (opt != '\1' && saw_files) { if (seq) { seq_free(seq); seq = NULL; } saw_files = 0; } if (seq == NULL) { if (!(seq = seq_init())) ERRNO_ERROR(1); } switch (opt) { case 'b': /* remove all extended entries */ if (seq_append_cmd(seq, CMD_REMOVE_EXTENDED_ACL, ACL_TYPE_ACCESS) || seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_DEFAULT)) ERRNO_ERROR(1); break; case 'k': /* remove default ACL */ if (seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_DEFAULT)) ERRNO_ERROR(1); break; case 'n': /* do not recalculate mask */ opt_recalculate = -1; break; case 'r': /* force recalculate mask */ opt_recalculate = 1; break; case 'd': /* operations apply to default ACL */ opt_promote = 1; break; case 's': /* set */ if (seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_ACCESS)) ERRNO_ERROR(1); seq_remove_acl_cmd = seq->s_last; if (seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_DEFAULT)) ERRNO_ERROR(1); seq_remove_default_acl_cmd = seq->s_last; seq_cmd = CMD_ENTRY_REPLACE; parse_mode = SEQ_PARSE_WITH_PERM | SEQ_PARSE_NO_RELATIVE; goto set_modify_delete; case 'm': /* modify */ seq_cmd = CMD_ENTRY_REPLACE; parse_mode = SEQ_PARSE_WITH_PERM; #if POSIXLY_CORRECT || 1 parse_mode |= SEQ_PARSE_NO_RELATIVE; #else if (posixly_correct) parse_mode |= SEQ_PARSE_NO_RELATIVE; else parse_mode |= SEQ_PARSE_ANY_RELATIVE; #endif goto set_modify_delete; case 'x': /* delete */ seq_cmd = CMD_REMOVE_ENTRY; parse_mode = SEQ_PARSE_NO_RELATIVE; #if POSIXLY_CORRECT parse_mode |= SEQ_PARSE_ANY_PERM; #else if (posixly_correct) parse_mode |= SEQ_PARSE_ANY_PERM; else parse_mode |= SEQ_PARSE_NO_PERM; #endif goto set_modify_delete; set_modify_delete: if (!posixly_correct) parse_mode |= SEQ_PARSE_DEFAULT; if (opt_promote) parse_mode |= SEQ_PROMOTE_ACL; if (parse_acl_seq(seq, optarg, &which, seq_cmd, parse_mode) != 0) { if (which < 0 || (size_t) which >= strlen(optarg)) { fprintf(stderr, _( "%s: Option " "-%c incomplete\n"), progname, opt); } else { fprintf(stderr, _( "%s: Option " "-%c: %s near " "character %d\n"), progname, opt, strerror(errno), which+1); } status = 2; goto cleanup; } break; case 'S': /* set from file */ if (seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_ACCESS)) ERRNO_ERROR(1); seq_remove_acl_cmd = seq->s_last; if (seq_append_cmd(seq, CMD_REMOVE_ACL, ACL_TYPE_DEFAULT)) ERRNO_ERROR(1); seq_remove_default_acl_cmd = seq->s_last; seq_cmd = CMD_ENTRY_REPLACE; parse_mode = SEQ_PARSE_WITH_PERM | SEQ_PARSE_NO_RELATIVE; goto set_modify_delete_from_file; case 'M': /* modify from file */ seq_cmd = CMD_ENTRY_REPLACE; parse_mode = SEQ_PARSE_WITH_PERM; #if POSIXLY_CORRECT || 1 parse_mode |= SEQ_PARSE_NO_RELATIVE; #else if (posixly_correct) parse_mode |= SEQ_PARSE_NO_RELATIVE; else parse_mode |= SEQ_PARSE_ANY_RELATIVE; #endif goto set_modify_delete_from_file; case 'X': /* delete from file */ seq_cmd = CMD_REMOVE_ENTRY; parse_mode = SEQ_PARSE_NO_RELATIVE; #if POSIXLY_CORRECT parse_mode |= SEQ_PARSE_ANY_PERM; #else if (posixly_correct) parse_mode |= SEQ_PARSE_ANY_PERM; else parse_mode |= SEQ_PARSE_NO_PERM; #endif goto set_modify_delete_from_file; set_modify_delete_from_file: if (!posixly_correct) parse_mode |= SEQ_PARSE_DEFAULT; if (opt_promote) parse_mode |= SEQ_PROMOTE_ACL; if (strcmp(optarg, "-") == 0) { file = stdin; } else { file = fopen(optarg, "r"); if (file == NULL) { fprintf(stderr, "%s: %s: %s\n", progname, xquote(optarg), strerror(errno)); status = 2; goto cleanup; } } lineno = 0; error = read_acl_seq(file, seq, seq_cmd, parse_mode, &lineno, NULL); if (file != stdin) { fclose(file); } if (error) { if (!errno) errno = EINVAL; if (file != stdin) { fprintf(stderr, _( "%s: %s in line " "%d of file %s\n"), progname, strerror(errno), lineno, xquote(optarg)); } else { fprintf(stderr, _( "%s: %s in line " "%d of standard " "input\n"), progname, strerror(errno), lineno); } status = 2; goto cleanup; } break; case '\1': /* file argument */ if (seq_empty(seq)) goto synopsis; saw_files = 1; status = next_file(optarg, seq); break; case 'B': /* restore ACL backup */ saw_files = 1; if (strcmp(optarg, "-") == 0) file = stdin; else { file = fopen(optarg, "r"); if (file == NULL) { fprintf(stderr, "%s: %s: %s\n", progname, xquote(optarg), strerror(errno)); status = 2; goto cleanup; } } status = restore(file, (file == stdin) ? NULL : optarg); if (file != stdin) fclose(file); if (status != 0) goto cleanup; break; case 'R': /* recursive */ opt_recursive = 1; break; case 'L': /* follow symlinks */ opt_walk_logical = 1; opt_walk_physical = 0; break; case 'P': /* do not follow symlinks */ opt_walk_logical = 0; opt_walk_physical = 1; break; case 't': /* test mode */ opt_test = 1; break; case 'v': /* print version and exit */ printf("%s " VERSION "\n", progname); status = 0; goto cleanup; case 'h': /* help! */ help(); status = 0; goto cleanup; case ':': /* option missing */ case '?': /* unknown option */ default: goto synopsis; } if (seq_remove_acl_cmd) { /* This was a set operation. Check if there are actually entries of ACL_TYPE_ACCESS; if there are none, we need to remove this command! */ if (!has_any_of_type(seq_remove_acl_cmd->c_next, ACL_TYPE_ACCESS)) seq_delete_cmd(seq, seq_remove_acl_cmd); } if (seq_remove_default_acl_cmd) { /* This was a set operation. Check if there are actually entries of ACL_TYPE_DEFAULT; if there are none, we need to remove this command! */ if (!has_any_of_type(seq_remove_default_acl_cmd->c_next, ACL_TYPE_DEFAULT)) seq_delete_cmd(seq, seq_remove_default_acl_cmd); } } while (optind < argc) { if (seq_empty(seq)) goto synopsis; saw_files = 1; status = next_file(argv[optind++], seq); } if (!saw_files) goto synopsis; goto cleanup; synopsis: fprintf(stderr, _("Usage: %s %s\n"), progname, cmd_line_spec); fprintf(stderr, _("Try `%s --help' for more information.\n"), progname); status = 2; goto cleanup; errno_error: fprintf(stderr, "%s: %s\n", progname, strerror(errno)); goto cleanup; cleanup: if (seq) seq_free(seq); return status; }
int restore( FILE *file, const char *filename) { char *path_p; struct stat st; uid_t uid; gid_t gid; mode_t mask, flags; struct do_set_args args = { }; int line = 0, backup_line; int error, status = 0; int chmod_required = 0; memset(&st, 0, sizeof(st)); for(;;) { backup_line = line; error = read_acl_comments(file, &line, &path_p, &uid, &gid, &flags); if (error < 0) { error = -error; goto fail; } if (error == 0) return status; if (path_p == NULL) { if (filename) { fprintf(stderr, _("%s: %s: No filename found " "in line %d, aborting\n"), progname, xquote(filename, "\n\r"), backup_line); } else { fprintf(stderr, _("%s: No filename found in " "line %d of standard input, " "aborting\n"), progname, backup_line); } status = 1; goto getout; } if (!(args.seq = seq_init())) goto fail_errno; 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_errno; error = read_acl_seq(file, args.seq, CMD_ENTRY_REPLACE, SEQ_PARSE_WITH_PERM | SEQ_PARSE_DEFAULT | SEQ_PARSE_MULTI, &line, NULL); if (error != 0) { fprintf(stderr, _("%s: %s: %s in line %d\n"), progname, xquote(filename, "\n\r"), strerror(errno), line); status = 1; goto getout; } error = stat(path_p, &st); if (opt_test && error != 0) { fprintf(stderr, "%s: %s: %s\n", progname, xquote(path_p, "\n\r"), strerror(errno)); status = 1; } args.mode = 0; error = do_set(path_p, &st, 0, &args); if (error != 0) { status = 1; goto resume; } if (uid != ACL_UNDEFINED_ID && uid != st.st_uid) st.st_uid = uid; else st.st_uid = -1; if (gid != ACL_UNDEFINED_ID && gid != st.st_gid) st.st_gid = gid; else st.st_gid = -1; if (!opt_test && (st.st_uid != -1 || st.st_gid != -1)) { if (chown(path_p, st.st_uid, st.st_gid) != 0) { fprintf(stderr, _("%s: %s: Cannot change " "owner/group: %s\n"), progname, xquote(path_p, "\n\r"), strerror(errno)); status = 1; } /* chown() clears setuid/setgid so force a chmod if * S_ISUID/S_ISGID was expected */ if ((st.st_mode & flags) & (S_ISUID | S_ISGID)) chmod_required = 1; } mask = S_ISUID | S_ISGID | S_ISVTX; if (chmod_required || ((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 (args.seq) { seq_free(args.seq); args.seq = NULL; } } getout: if (path_p) { free(path_p); path_p = NULL; } if (args.seq) { seq_free(args.seq); args.seq = NULL; } return status; fail_errno: error = errno; fail: fprintf(stderr, "%s: %s: %s\n", progname, xquote(filename, "\n\r"), strerror(error)); status = 1; goto getout; }