summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabiano Fidêncio <fidencio@redhat.com>2017-08-02 14:00:03 +0200
committerJakub Hrozek <jhrozek@redhat.com>2017-08-28 20:40:53 +0200
commit6f466e0a3d950d21bd750ef53cb93b75dc023f9e (patch)
treef5329bc033702fc13a185901cb8631e842cd9f60
parent5b93634c7f0e34f69b4cf8fb9b2e77b9179024a7 (diff)
downloadsssd-6f466e0a3d950d21bd750ef53cb93b75dc023f9e.tar.gz
sssd-6f466e0a3d950d21bd750ef53cb93b75dc023f9e.tar.xz
sssd-6f466e0a3d950d21bd750ef53cb93b75dc023f9e.zip
UTIL: Add sss_create_dir()
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 <fidencio@redhat.com> Reviewed-by: Pavel Březina <pbrezina@redhat.com> Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-rw-r--r--src/tests/files-tests.c37
-rw-r--r--src/util/files.c77
-rw-r--r--src/util/util.h5
3 files changed, 119 insertions, 0 deletions
diff --git a/src/tests/files-tests.c b/src/tests/files-tests.c
index 9feb9274a..1ccf404b9 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 5827b29d8..33b21e2ea 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 80411ec91..3d8bfe479 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);