mirror of
https://github.com/systemd/systemd.git
synced 2025-01-26 14:04:03 +03:00
chase-symlinks: Add CHASE_MKDIR_0755
This commit is contained in:
parent
28aa650eb7
commit
e864dfa671
@ -98,6 +98,9 @@ int chase_symlinks_at(
|
||||
if ((flags & CHASE_STEP) && ret_fd)
|
||||
return -EINVAL;
|
||||
|
||||
if (FLAGS_SET(flags, CHASE_MKDIR_0755|CHASE_NONEXISTENT))
|
||||
return -EINVAL;
|
||||
|
||||
if (isempty(path))
|
||||
path = ".";
|
||||
|
||||
@ -172,7 +175,7 @@ int chase_symlinks_at(
|
||||
|
||||
if (!(flags &
|
||||
(CHASE_AT_RESOLVE_IN_ROOT|CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP|
|
||||
CHASE_PROHIBIT_SYMLINKS)) &&
|
||||
CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755)) &&
|
||||
!ret_path && ret_fd) {
|
||||
|
||||
/* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root
|
||||
@ -295,15 +298,15 @@ int chase_symlinks_at(
|
||||
}
|
||||
|
||||
/* Otherwise let's see what this is. */
|
||||
child = openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH);
|
||||
if (child < 0) {
|
||||
if (errno == ENOENT &&
|
||||
(flags & CHASE_NONEXISTENT) &&
|
||||
(isempty(todo) || path_is_safe(todo))) {
|
||||
/* If CHASE_NONEXISTENT is set, and the path does not exist, then
|
||||
* that's OK, return what we got so far. But don't allow this if the
|
||||
* remaining path contains "../" or something else weird. */
|
||||
child = r = RET_NERRNO(openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH));
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
|
||||
if (!isempty(todo) && !path_is_safe(todo))
|
||||
return r;
|
||||
|
||||
if (flags & CHASE_NONEXISTENT) {
|
||||
if (!path_extend(&done, first, todo))
|
||||
return -ENOMEM;
|
||||
|
||||
@ -311,7 +314,12 @@ int chase_symlinks_at(
|
||||
break;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
if (!(flags & CHASE_MKDIR_0755))
|
||||
return r;
|
||||
|
||||
child = open_mkdir_at(fd, first, O_CLOEXEC|O_PATH|O_EXCL, 0755);
|
||||
if (child < 0)
|
||||
return child;
|
||||
}
|
||||
|
||||
if (fstat(child, &st) < 0)
|
||||
@ -390,7 +398,7 @@ int chase_symlinks_at(
|
||||
close_and_replace(fd, child);
|
||||
}
|
||||
|
||||
if (flags & CHASE_PARENT) {
|
||||
if (flags & (CHASE_PARENT|CHASE_MKDIR_0755)) {
|
||||
r = fd_verify_directory(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -548,7 +556,7 @@ int chase_symlinks_and_open(
|
||||
return -EINVAL;
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0) {
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
r = open(path, open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
|
||||
if (r < 0)
|
||||
@ -590,7 +598,7 @@ int chase_symlinks_and_opendir(
|
||||
return -EINVAL;
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0) {
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
d = opendir(path);
|
||||
if (!d)
|
||||
@ -635,7 +643,7 @@ int chase_symlinks_and_stat(
|
||||
return -EINVAL;
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0 && !ret_fd) {
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0 && !ret_fd) {
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
|
||||
if (fstatat(AT_FDCWD, path, ret_stat, FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0) < 0)
|
||||
@ -678,7 +686,7 @@ int chase_symlinks_and_access(
|
||||
return -EINVAL;
|
||||
|
||||
if (empty_or_root(root) && !ret_path &&
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT)) == 0 && !ret_fd) {
|
||||
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0 && !ret_fd) {
|
||||
/* Shortcut this call if none of the special features of this call are requested */
|
||||
|
||||
if (faccessat(AT_FDCWD, path, access_mode, FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0) < 0)
|
||||
|
@ -21,6 +21,7 @@ typedef enum ChaseSymlinksFlags {
|
||||
* relative to the given directory fd instead of root. */
|
||||
CHASE_PROHIBIT_SYMLINKS = 1 << 9, /* Refuse all symlinks */
|
||||
CHASE_PARENT = 1 << 10, /* Chase the parent directory of the given path. */
|
||||
CHASE_MKDIR_0755 = 1 << 11, /* Create any missing directories in the given path. */
|
||||
} ChaseSymlinksFlags;
|
||||
|
||||
bool unsafe_transition(const struct stat *a, const struct stat *b);
|
||||
|
@ -486,6 +486,20 @@ TEST(chase_symlinks_at) {
|
||||
assert_se(chase_symlinks_at(tfd, "chase", CHASE_NONEXISTENT|CHASE_PARENT, &result, NULL) >= 0);
|
||||
assert_se(streq(result, "."));
|
||||
result = mfree(result);
|
||||
|
||||
/* Test CHASE_MKDIR_0755 */
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "m/k/d/i/r", CHASE_MKDIR_0755, &result, NULL) >= 0);
|
||||
assert_se(faccessat(tfd, "m/k/d/i/r", F_OK, 0) >= 0);
|
||||
assert_se(streq(result, "m/k/d/i/r"));
|
||||
result = mfree(result);
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "m/../q", CHASE_MKDIR_0755, &result, NULL) >= 0);
|
||||
assert_se(faccessat(tfd, "q", F_OK, 0) >= 0);
|
||||
assert_se(streq(result, "q"));
|
||||
result = mfree(result);
|
||||
|
||||
assert_se(chase_symlinks_at(tfd, "i/../p", CHASE_MKDIR_0755, NULL, NULL) == -ENOENT);
|
||||
}
|
||||
|
||||
TEST(unlink_noerrno) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user