Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}