From 6f466e0a3d950d21bd750ef53cb93b75dc023f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Wed, 2 Aug 2017 14:00:03 +0200 Subject: [PATCH 52/93] UTIL: Add sss_create_dir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The newly added function helps us to create a new dir avoiding a possible TUCTOU issue. It's going to be used by the new session provider code. A simple test for this new function has also been provided. Related: https://pagure.io/SSSD/sssd/issue/2995 Signed-off-by: Fabiano Fidêncio Reviewed-by: Pavel Březina Reviewed-by: Jakub Hrozek --- src/tests/files-tests.c | 37 ++++++++++++++++++++++++ src/util/files.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ src/util/util.h | 5 ++++ 3 files changed, 119 insertions(+) diff --git a/src/tests/files-tests.c b/src/tests/files-tests.c index 9feb9274ace02dd977950b8de220ee1f1aa18e65..1ccf404b94dc5518308c54380117c1162dc85f22 100644 --- a/src/tests/files-tests.c +++ b/src/tests/files-tests.c @@ -378,6 +378,42 @@ START_TEST(test_copy_node) } END_TEST +START_TEST(test_create_dir) +{ + int ret; + char origpath[PATH_MAX+1]; + char *new_dir; + struct stat info; + + errno = 0; + + fail_unless(getcwd(origpath, PATH_MAX) == origpath, "Cannot getcwd\n"); + fail_unless(errno == 0, "Cannot getcwd\n"); + + /* create a dir */ + ret = sss_create_dir(dir_path, "testdir", S_IRUSR | S_IXUSR, uid, gid); + fail_unless(ret == EOK, "cannot create dir: %s", strerror(ret)); + + new_dir = talloc_asprintf(NULL, "%s/testdir", dir_path); + ret = stat(new_dir, &info); + fail_unless(ret == EOK, "failed to stat '%s'\n", new_dir); + + /* check the dir has been created */ + fail_unless(S_ISDIR(info.st_mode) != 0, "'%s' is not a dir.\n", new_dir); + + /* check the permissions are okay */ + fail_unless((info.st_mode & S_IRUSR) != 0, "Read permission is not set\n"); + fail_unless((info.st_mode & S_IWUSR) == 0, "Write permission is set\n"); + fail_unless((info.st_mode & S_IXUSR) != 0, "Exec permission is not set\n"); + + /* check the owner is okay */ + fail_unless(info.st_uid == uid, "Dir created with the wrong uid\n"); + fail_unless(info.st_gid == gid, "Dir created with the wrong gid\n"); + + talloc_free(new_dir); +} +END_TEST + static Suite *files_suite(void) { Suite *s = suite_create("files_suite"); @@ -393,6 +429,7 @@ static Suite *files_suite(void) tcase_add_test(tc_files, test_copy_file); tcase_add_test(tc_files, test_copy_symlink); tcase_add_test(tc_files, test_copy_node); + tcase_add_test(tc_files, test_create_dir); suite_add_tcase(s, tc_files); return s; diff --git a/src/util/files.c b/src/util/files.c index 5827b29d8b5cf13248514f693e859d42335069d9..33b21e2ea3bad854d5a8e831a84ad4d768b7f9c0 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -807,3 +807,80 @@ fail: talloc_free(cctx); return ret; } + +int sss_create_dir(const char *parent_dir_path, + const char *dir_name, + mode_t mode, + uid_t uid, gid_t gid) +{ + TALLOC_CTX *tmp_ctx; + char *dir_path; + int ret = EOK; + int parent_dir_fd = -1; + int dir_fd = -1; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + parent_dir_fd = sss_open_cloexec(parent_dir_path, O_RDONLY | O_DIRECTORY, + &ret); + if (parent_dir_fd == -1) { + DEBUG(SSSDBG_TRACE_FUNC, + "Cannot open() directory '%s' [%d]: %s\n", + parent_dir_path, ret, sss_strerror(ret)); + goto fail; + } + + dir_path = talloc_asprintf(tmp_ctx, "%s/%s", parent_dir_path, dir_name); + if (dir_path == NULL) { + ret = ENOMEM; + goto fail; + } + + errno = 0; + ret = mkdirat(parent_dir_fd, dir_name, mode); + if (ret == -1) { + if (errno == EEXIST) { + ret = EOK; + DEBUG(SSSDBG_TRACE_FUNC, + "Directory '%s' already created!\n", dir_path); + } else { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Error reading '%s': %s\n", parent_dir_path, strerror(ret)); + goto fail; + } + } + + dir_fd = sss_open_cloexec(dir_path, O_RDONLY | O_DIRECTORY, &ret); + if (dir_fd == -1) { + DEBUG(SSSDBG_TRACE_FUNC, + "Cannot open() directory '%s' [%d]: %s\n", + dir_path, ret, sss_strerror(ret)); + goto fail; + } + + errno = 0; + ret = fchown(dir_fd, uid, gid); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to own the newly created directory '%s' [%d]: %s\n", + dir_path, ret, sss_strerror(ret)); + goto fail; + } + + ret = EOK; + +fail: + if (parent_dir_fd != -1) { + close(parent_dir_fd); + } + if (dir_fd != -1) { + close(dir_fd); + } + talloc_free(tmp_ctx); + return ret; +} diff --git a/src/util/util.h b/src/util/util.h index 80411ec91046b7dc7993b8d175fedebd2b70a79a..3d8bfe4795e976294b565c0869e3b842cf318efd 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -696,6 +696,11 @@ int sss_copy_file_secure(const char *src, uid_t uid, gid_t gid, bool force); +int sss_create_dir(const char *parent_dir_path, + const char *dir_name, + mode_t mode, + uid_t uid, gid_t gid); + /* from selinux.c */ int selinux_file_context(const char *dst_name); int reset_selinux_file_context(void); -- 2.14.1