diff --git a/src/basic/chase-symlinks.c b/src/basic/chase-symlinks.c index 61f8b3351b..e93419d635 100644 --- a/src/basic/chase-symlinks.c +++ b/src/basic/chase-symlinks.c @@ -24,7 +24,7 @@ bool unsafe_transition(const struct stat *a, const struct stat *b) { return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */ } -static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) { +static int log_unsafe_transition(int a, int b, const char *path, ChaseSymlinksFlags flags) { _cleanup_free_ char *n1 = NULL, *n2 = NULL, *user_a = NULL, *user_b = NULL; struct stat st; @@ -44,7 +44,7 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) strna(n1), strna(user_a), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), strna(n2), strna(user_b), path); } -static int log_autofs_mount_point(int fd, const char *path, unsigned flags) { +static int log_autofs_mount_point(int fd, const char *path, ChaseSymlinksFlags flags) { _cleanup_free_ char *n1 = NULL; if (!FLAGS_SET(flags, CHASE_WARN)) @@ -57,7 +57,13 @@ static int log_autofs_mount_point(int fd, const char *path, unsigned flags) { strna(n1), path); } -int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) { +int chase_symlinks( + const char *path, + const char *original_root, + ChaseSymlinksFlags flags, + char **ret_path, + int *ret_fd) { + _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL; _cleanup_close_ int fd = -1; unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */ @@ -78,6 +84,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (isempty(path)) return -EINVAL; + /* We don't support relative paths in combination with a root directory */ + if (FLAGS_SET(flags, CHASE_PREFIX_ROOT) && !path_is_absolute(path)) + return -EINVAL; + /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following * symlinks relative to a root directory, instead of the root of the host. * @@ -155,19 +165,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, path_simplify(root); if (flags & CHASE_PREFIX_ROOT) { - /* We don't support relative paths in combination with a root directory */ - if (!path_is_absolute(path)) - return -EINVAL; - - path = prefix_roota(root, path); + buffer = path_join(root, path); + if (!buffer) + return -ENOMEM; } } - r = path_make_absolute_cwd(path, &buffer); - if (r < 0) - return r; + if (!buffer) { + r = path_make_absolute_cwd(path, &buffer); + if (r < 0) + return r; + } - fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH); + fd = open(empty_to_root(root), O_CLOEXEC|O_DIRECTORY|O_PATH); if (fd < 0) return -errno; @@ -193,6 +203,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, todo = buffer; done = strdup("/"); } + if (!done) + return -ENOMEM; for (;;) { _cleanup_free_ char *first = NULL; @@ -200,7 +212,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, struct stat st; const char *e; - r = path_find_first_component(&todo, true, &e); + r = path_find_first_component(&todo, /* accept_dot_dot= */ true, &e); if (r < 0) return r; if (r == 0) { /* We reached the end. */ @@ -224,9 +236,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (empty_or_root(done)) continue; - parent = dirname_malloc(done); - if (!parent) - return -ENOMEM; + r = path_extract_directory(done, &parent); + if (r < 0) + return r; /* Don't allow this to leave the root dir. */ if (root && @@ -311,7 +323,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * directory as base. */ safe_close(fd); - fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH); + fd = open(empty_to_root(root), O_CLOEXEC|O_DIRECTORY|O_PATH); if (fd < 0) return -errno; @@ -375,7 +387,7 @@ chased_one: const char *e; /* todo may contain slashes at the beginning. */ - r = path_find_first_component(&todo, true, &e); + r = path_find_first_component(&todo, /* accept_dot_dot= */ true, &e); if (r < 0) return r; if (r == 0) @@ -397,7 +409,7 @@ chased_one: int chase_symlinks_and_open( const char *path, const char *root, - unsigned chase_flags, + ChaseSymlinksFlags chase_flags, int open_flags, char **ret_path) { @@ -435,7 +447,7 @@ int chase_symlinks_and_open( int chase_symlinks_and_opendir( const char *path, const char *root, - unsigned chase_flags, + ChaseSymlinksFlags chase_flags, char **ret_path, DIR **ret_dir) { @@ -478,7 +490,7 @@ int chase_symlinks_and_opendir( int chase_symlinks_and_stat( const char *path, const char *root, - unsigned chase_flags, + ChaseSymlinksFlags chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd) { @@ -520,7 +532,7 @@ int chase_symlinks_and_stat( int chase_symlinks_and_fopen_unlocked( const char *path, const char *root, - unsigned chase_flags, + ChaseSymlinksFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file) { diff --git a/src/basic/chase-symlinks.h b/src/basic/chase-symlinks.h index e2b22fe041..491138a698 100644 --- a/src/basic/chase-symlinks.h +++ b/src/basic/chase-symlinks.h @@ -6,7 +6,7 @@ #include "stat-util.h" -enum { +typedef enum ChaseSymlinksFlags { CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */ CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */ CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */ @@ -16,17 +16,17 @@ enum { CHASE_NOFOLLOW = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's * right-most component refers to symlink, return O_PATH fd of the symlink. */ CHASE_WARN = 1 << 7, /* Emit an appropriate warning when an error is encountered */ -}; +} ChaseSymlinksFlags; bool unsafe_transition(const struct stat *a, const struct stat *b); /* How many iterations to execute before returning -ELOOP */ #define CHASE_SYMLINKS_MAX 32 -int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret_path, int *ret_fd); +int chase_symlinks(const char *path_with_prefix, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, int *ret_fd); -int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path); -int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir); -int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd); +int chase_symlinks_and_open(const char *path, const char *root, ChaseSymlinksFlags chase_flags, int open_flags, char **ret_path); +int chase_symlinks_and_opendir(const char *path, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, DIR **ret_dir); +int chase_symlinks_and_stat(const char *path, const char *root, ChaseSymlinksFlags chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd); -int chase_symlinks_and_fopen_unlocked(const char *path, const char *root, unsigned chase_flags, const char *open_flags, char **ret_path, FILE **ret_file); +int chase_symlinks_and_fopen_unlocked(const char *path, const char *root, ChaseSymlinksFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);