|
|
3a204fb |
From fdc64c5aafe435e34c4369ae8504d98ff57d7350 Mon Sep 17 00:00:00 2001
|
|
|
3a204fb |
From: Jakub Filak <jfilak@redhat.com>
|
|
|
3a204fb |
Date: Thu, 28 May 2015 12:32:01 +0200
|
|
|
3a204fb |
Subject: [PATCH] dd: add support for meta-data
|
|
|
3a204fb |
|
|
|
3a204fb |
Store the meta-data as plain text files in the dump directory's
|
|
|
3a204fb |
sub-directory called '.libreport'.
|
|
|
3a204fb |
|
|
|
3a204fb |
I chose this name to allow other tools (which do not exist yet) to create
|
|
|
3a204fb |
their own directories and files.
|
|
|
3a204fb |
|
|
|
3a204fb |
Related: #354
|
|
|
3a204fb |
|
|
|
3a204fb |
Signed-off-by: Jakub Filak <jfilak@redhat.com>
|
|
|
3a204fb |
---
|
|
|
3a204fb |
src/include/dump_dir.h | 4 +
|
|
|
3a204fb |
src/lib/dump_dir.c | 511 ++++++++++++++++++++++++++++++++++++++++++-------
|
|
|
3a204fb |
tests/dump_dir.at | 171 +++++++++++++++++
|
|
|
3a204fb |
3 files changed, 618 insertions(+), 68 deletions(-)
|
|
|
3a204fb |
|
|
|
3a204fb |
diff --git a/src/include/dump_dir.h b/src/include/dump_dir.h
|
|
|
3a204fb |
index b613e0b..f33eb99 100644
|
|
|
3a204fb |
--- a/src/include/dump_dir.h
|
|
|
3a204fb |
+++ b/src/include/dump_dir.h
|
|
|
3a204fb |
@@ -75,6 +75,10 @@ struct dump_dir {
|
|
|
3a204fb |
*/
|
|
|
3a204fb |
int owns_lock;
|
|
|
3a204fb |
int dd_fd;
|
|
|
3a204fb |
+ /* Never use this member directly, it is intialized on demand in
|
|
|
3a204fb |
+ * dd_get_meta_data_dir_fd()
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+ int dd_md_fd;
|
|
|
3a204fb |
};
|
|
|
3a204fb |
|
|
|
3a204fb |
void dd_close(struct dump_dir *dd);
|
|
|
3a204fb |
diff --git a/src/lib/dump_dir.c b/src/lib/dump_dir.c
|
|
|
3a204fb |
index 4dcfa66..aed2de0 100644
|
|
|
3a204fb |
--- a/src/lib/dump_dir.c
|
|
|
3a204fb |
+++ b/src/lib/dump_dir.c
|
|
|
3a204fb |
@@ -83,6 +83,24 @@
|
|
|
3a204fb |
#define RMDIR_FAIL_USLEEP (10*1000)
|
|
|
3a204fb |
#define RMDIR_FAIL_COUNT 50
|
|
|
3a204fb |
|
|
|
3a204fb |
+// A sub-directory of a dump directory where the meta-data such as owner are
|
|
|
3a204fb |
+// stored. The meta-data directory must have same owner, group and mode as its
|
|
|
3a204fb |
+// parent dump directory. It is not a fatal error, if the meta-data directory
|
|
|
3a204fb |
+// does not exist (backward compatibility).
|
|
|
3a204fb |
+#define META_DATA_DIR_NAME ".libreport"
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+enum {
|
|
|
3a204fb |
+ /* Try to create meta-data dir if it does not exist */
|
|
|
3a204fb |
+ DD_MD_GET_CREATE = 1 << 0,
|
|
|
3a204fb |
+};
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+// a little trick to copy read bits from file mode to exec bit of dir mode
|
|
|
3a204fb |
+// * mode of dump directory is in the form of 640 (no X) because we create
|
|
|
3a204fb |
+// files more often then we play with directories
|
|
|
3a204fb |
+// * so if we want to get real mode of the directory we have to copy the read
|
|
|
3a204fb |
+// bits
|
|
|
3a204fb |
+#define DD_MODE_TO_DIR_MODE(mode) ((mode) | (((mode) & 0444) >> 2))
|
|
|
3a204fb |
+
|
|
|
3a204fb |
|
|
|
3a204fb |
static char *load_text_file(const char *path, unsigned flags);
|
|
|
3a204fb |
static char *load_text_file_at(int dir_fd, const char *name, unsigned flags);
|
|
|
3a204fb |
@@ -112,6 +130,12 @@ static bool exist_file_dir_at(int dir_fd, const char *name)
|
|
|
3a204fb |
return false;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
+/* A valid dump dir element name is correct filename and is not a name of any
|
|
|
3a204fb |
+ * internal file or directory.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+#define dd_validate_element_name(name) \
|
|
|
3a204fb |
+ (str_is_correct_filename(name) && (strcmp(META_DATA_DIR_NAME, name) != 0))
|
|
|
3a204fb |
+
|
|
|
3a204fb |
/* Opens the file in the three following steps:
|
|
|
3a204fb |
* 1. open the file with O_PATH (get a file descriptor for operations with
|
|
|
3a204fb |
* inode) and O_NOFOLLOW (do not dereference symbolick links)
|
|
|
3a204fb |
@@ -397,18 +421,28 @@ static inline struct dump_dir *dd_init(void)
|
|
|
3a204fb |
struct dump_dir* dd = (struct dump_dir*)xzalloc(sizeof(struct dump_dir));
|
|
|
3a204fb |
dd->dd_time = -1;
|
|
|
3a204fb |
dd->dd_fd = -1;
|
|
|
3a204fb |
+ dd->dd_md_fd = -1;
|
|
|
3a204fb |
return dd;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
int dd_exist(const struct dump_dir *dd, const char *name)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
error_msg_and_die("Cannot test existence. '%s' is not a valid file name", name);
|
|
|
3a204fb |
|
|
|
3a204fb |
const int ret = exist_file_dir_at(dd->dd_fd, name);
|
|
|
3a204fb |
return ret;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
+static void dd_close_meta_data_dir(struct dump_dir *dd)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ if (dd->dd_md_fd < 0)
|
|
|
3a204fb |
+ return;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ close(dd->dd_md_fd);
|
|
|
3a204fb |
+ dd->dd_md_fd = -1;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
void dd_close(struct dump_dir *dd)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
if (!dd)
|
|
|
3a204fb |
@@ -419,6 +453,8 @@ void dd_close(struct dump_dir *dd)
|
|
|
3a204fb |
if (dd->dd_fd >= 0)
|
|
|
3a204fb |
close(dd->dd_fd);
|
|
|
3a204fb |
|
|
|
3a204fb |
+ dd_close_meta_data_dir(dd);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
if (dd->next_dir)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
closedir(dd->next_dir);
|
|
|
3a204fb |
@@ -430,6 +466,255 @@ void dd_close(struct dump_dir *dd)
|
|
|
3a204fb |
free(dd);
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
+static int dd_create_subdir(int dd_fd, const char *dirname, uid_t dd_uid, gid_t dd_gid, mode_t dd_mode)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ if (mkdirat(dd_fd, dirname, dd_mode) < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Can't create directory '%s'", dirname);
|
|
|
3a204fb |
+ return -1;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ int dd_md_fd = openat(dd_fd, dirname, O_DIRECTORY | O_NOFOLLOW);
|
|
|
3a204fb |
+ if (dd_md_fd < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Can't open newly created directory '%s'", dirname);
|
|
|
3a204fb |
+ goto fail_open;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (dd_uid != (uid_t)-1)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ if (fchown(dd_md_fd, dd_uid, dd_gid) != 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Can't change owner and group of '%s'", dirname);
|
|
|
3a204fb |
+ goto fail_modify;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* mkdir's mode (above) can be affected by umask, fix it */
|
|
|
3a204fb |
+ if (fchmod(dd_md_fd, dd_mode) == -1)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Can't change mode of '%s'", dirname);
|
|
|
3a204fb |
+ goto fail_modify;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return dd_md_fd;
|
|
|
3a204fb |
+fail_modify:
|
|
|
3a204fb |
+ close(dd_md_fd);
|
|
|
3a204fb |
+fail_open:
|
|
|
3a204fb |
+ if (unlinkat(dd_fd, dirname, AT_REMOVEDIR) < 0)
|
|
|
3a204fb |
+ perror_msg("Fialed to unlink '%s' while cleaning up after failure", dirname);
|
|
|
3a204fb |
+ return -1;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+/* Opens the meta-data directory, checks its file system attributes and returns
|
|
|
3a204fb |
+ * its file descriptor.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * The meta-data directory must have the same file system attributes as the
|
|
|
3a204fb |
+ * parent dump directory in order to avoid unexpected situations and detects
|
|
|
3a204fb |
+ * program errors (it is an error to modify bits of the dump directory and
|
|
|
3a204fb |
+ * forgot to update the meta-data directory).
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * Keep on mind that the old dump directories might miss the meta-data directory
|
|
|
3a204fb |
+ * so the return value -ENOENT does not necessarily need to be fatal.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+static int dd_open_meta_data_dir(struct dump_dir *dd)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ int md_dir_fd = openat(dd->dd_fd, META_DATA_DIR_NAME, O_DIRECTORY | O_NOFOLLOW);
|
|
|
3a204fb |
+ if (md_dir_fd < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ md_dir_fd = -errno;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* ENOENT is not critical */
|
|
|
3a204fb |
+ if (errno != ENOENT)
|
|
|
3a204fb |
+ log_warning("Can't open meta-data '"META_DATA_DIR_NAME"'");
|
|
|
3a204fb |
+ else
|
|
|
3a204fb |
+ log_info("The dump dir doesn't contain '"META_DATA_DIR_NAME"'");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ goto finito;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ struct stat md_sb;
|
|
|
3a204fb |
+ if (fstat(md_dir_fd, &md_sb) < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ log_debug("Can't stat '"META_DATA_DIR_NAME"'");
|
|
|
3a204fb |
+ goto fail;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* Test only permission bits, ignore SUID, SGID, etc. */
|
|
|
3a204fb |
+ const mode_t md_mode = md_sb.st_mode & 0777;
|
|
|
3a204fb |
+ const mode_t dd_mode = DD_MODE_TO_DIR_MODE(dd->mode);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if ( md_sb.st_uid != dd->dd_uid
|
|
|
3a204fb |
+ || md_sb.st_gid != dd->dd_gid
|
|
|
3a204fb |
+ || md_mode != dd_mode)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ log_debug("'"META_DATA_DIR_NAME"' has different attributes than the dump dir, '%d'='%d', '%d'='%d', %o = %o",
|
|
|
3a204fb |
+ md_sb.st_uid, dd->dd_uid, md_sb.st_gid, dd->dd_gid, md_mode, dd_mode);
|
|
|
3a204fb |
+ goto fail;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+finito:
|
|
|
3a204fb |
+ return md_dir_fd;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+fail:
|
|
|
3a204fb |
+ close(md_dir_fd);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return -EINVAL;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+/* Returns a file descriptor to the meta-data directory. Can be configured to
|
|
|
3a204fb |
+ * create the directory if it does not exist.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * This function enables lazy initialization of the meta-data directory.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+static int dd_get_meta_data_dir_fd(struct dump_dir *dd, int flags)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ if (dd->dd_md_fd < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ dd->dd_md_fd = dd_open_meta_data_dir(dd);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if ( dd->dd_md_fd == -ENOENT
|
|
|
3a204fb |
+ && (flags & DD_MD_GET_CREATE))
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ dd->dd_md_fd = dd_create_subdir(dd->dd_fd,
|
|
|
3a204fb |
+ META_DATA_DIR_NAME,
|
|
|
3a204fb |
+ dd->dd_uid,
|
|
|
3a204fb |
+ dd->dd_gid,
|
|
|
3a204fb |
+ DD_MODE_TO_DIR_MODE(dd->mode));
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return dd->dd_md_fd;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+/* A helper function useful for traversing directories.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * DIR* d opendir(dir_fd); ... closedir(d); closes also dir_fd but we want to
|
|
|
3a204fb |
+ * keep it opened.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+static int fdreopen(int dir_fd, DIR **d)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ int opendir_fd = dup(dir_fd);
|
|
|
3a204fb |
+ if (opendir_fd < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("dup(dir_fd)");
|
|
|
3a204fb |
+ return -EBADFD;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ lseek(opendir_fd, SEEK_SET, 0);
|
|
|
3a204fb |
+ *d = fdopendir(opendir_fd);
|
|
|
3a204fb |
+ if (!*d)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ int ret = -errno;
|
|
|
3a204fb |
+ close(opendir_fd);
|
|
|
3a204fb |
+ perror_msg("fdopendir(dir_fd)");
|
|
|
3a204fb |
+ return ret;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* 'opendir_fd' will be closed with 'd' */
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+/* A macro for going through the entries of a directory referenced as a file
|
|
|
3a204fb |
+ * descriptor.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * Usage:
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * FOREACH_REGULAR_FILE_AS_FD_AT_BEGIN(dir_fd)
|
|
|
3a204fb |
+ * {
|
|
|
3a204fb |
+ * printf("Short name '%s'", dent->d_name);
|
|
|
3a204fb |
+ * printf("File descriptor %d", fd);
|
|
|
3a204fb |
+ * }
|
|
|
3a204fb |
+ * FOREACH_REGULAR_FILE_AS_FD_AT_END
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+#define FOREACH_REGULAR_FILE_AS_FD_AT_BEGIN(dir_fd) \
|
|
|
3a204fb |
+ DIR *d; \
|
|
|
3a204fb |
+ struct dirent *dent; \
|
|
|
3a204fb |
+ if (fdreopen(dir_fd, &d) < 0) return -1; \
|
|
|
3a204fb |
+ while ((dent = readdir(d)) != NULL) \
|
|
|
3a204fb |
+ { \
|
|
|
3a204fb |
+ if (dot_or_dotdot(dent->d_name)) continue; \
|
|
|
3a204fb |
+ int fd = secure_openat_read(dirfd(d), dent->d_name); \
|
|
|
3a204fb |
+ if (fd >= 0)
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+#define FOREACH_REGULAR_FILE_AS_FD_AT_END \
|
|
|
3a204fb |
+ close(fd); \
|
|
|
3a204fb |
+ } \
|
|
|
3a204fb |
+ closedir(d);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+/* Sets attributes of the meta-data directory and its contents to the same
|
|
|
3a204fb |
+ * attributes of the parent dump directory.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+static int dd_sanitize_mode_meta_data(struct dump_dir *dd)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ if (!dd->locked)
|
|
|
3a204fb |
+ error_msg_and_die("%s: dump_dir is not opened", __func__); /* bug */
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ int dd_md_fd = dd_get_meta_data_dir_fd(dd, /*no create*/0);
|
|
|
3a204fb |
+ if (dd_md_fd < 0)
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ int res = fchmod(dd_md_fd, DD_MODE_TO_DIR_MODE(dd->mode));
|
|
|
3a204fb |
+ if (res < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Failed to chmod meta-data sub-dir");
|
|
|
3a204fb |
+ return res;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ FOREACH_REGULAR_FILE_AS_FD_AT_BEGIN(dd_md_fd)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ log_debug("chmoding %s", dent->d_name);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ res = fchmod(fd, dd->mode);
|
|
|
3a204fb |
+ if (res)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("fchmod('%s')", dent->d_name);
|
|
|
3a204fb |
+ break;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ FOREACH_REGULAR_FILE_AS_FD_AT_END
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+/* Sets owner and group of the meta-data directory and its contents to the same
|
|
|
3a204fb |
+ * attributes of the parent dump directory.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+static int dd_chown_meta_data(struct dump_dir *dd, uid_t uid, gid_t gid)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ if (!dd->locked)
|
|
|
3a204fb |
+ error_msg_and_die("%s: dump_dir is not opened", __func__); /* bug */
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ int dd_md_fd = dd_get_meta_data_dir_fd(dd, /*no create*/0);
|
|
|
3a204fb |
+ if (dd_md_fd < 0)
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ int res = fchown(dd_md_fd, uid, gid);
|
|
|
3a204fb |
+ if (res < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Failed to chown meta-data sub-dir");
|
|
|
3a204fb |
+ return res;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ FOREACH_REGULAR_FILE_AS_FD_AT_BEGIN(dd_md_fd)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ log_debug("%s: chowning %s", __func__, dent->d_name);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ res = fchown(fd, uid, gid);
|
|
|
3a204fb |
+ if (res)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("fchown('%s')", dent->d_name);
|
|
|
3a204fb |
+ break;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ FOREACH_REGULAR_FILE_AS_FD_AT_END
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return res;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
static char* rm_trailing_slashes(const char *dir)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
unsigned len = strlen(dir);
|
|
|
3a204fb |
@@ -455,45 +740,41 @@ static struct dump_dir *dd_do_open(struct dump_dir *dd, const char *dir, int fla
|
|
|
3a204fb |
/* & 0666 should remove the executable bit */
|
|
|
3a204fb |
dd->mode = (stat_buf.st_mode & 0666);
|
|
|
3a204fb |
|
|
|
3a204fb |
- dd->dd_uid = (uid_t)-1L;
|
|
|
3a204fb |
- dd->dd_gid = (gid_t)-1L;
|
|
|
3a204fb |
+ /* We want to have dd_uid and dd_gid always initialized. But we have to
|
|
|
3a204fb |
+ * initialize it in the way which does not prevent non-privileged user
|
|
|
3a204fb |
+ * from saving data in their dump directories.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * Non-privileged users are not allowed to change the group to
|
|
|
3a204fb |
+ * 'abrt' so we have to use their GID.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * If the caller is super-user, we have to use dd's fs owner and fs
|
|
|
3a204fb |
+ * group, because he can do everything and the data must be readable by
|
|
|
3a204fb |
+ * the real owner.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * We always use fs uid, because non-privileged users must own the
|
|
|
3a204fb |
+ * directory and super-user must use fs owner.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+ dd->dd_uid = stat_buf.st_uid;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* We use fs group only if the caller is super-user, because we want to
|
|
|
3a204fb |
+ * make sure non-privileged users can modify elements (libreport call
|
|
|
3a204fb |
+ * chown(dd_uid, dd_gid) after modifying an element) and the modified
|
|
|
3a204fb |
+ * elements do not have super-user's group.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+ dd->dd_gid = getegid();
|
|
|
3a204fb |
if (geteuid() == 0)
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- /* In case caller would want to create more files, he'll need uid:gid */
|
|
|
3a204fb |
- if (fstat(dd->dd_fd, &stat_buf) != 0)
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- error_msg("Can't stat '%s'", dd->dd_dirname);
|
|
|
3a204fb |
- dd_close(dd);
|
|
|
3a204fb |
- return NULL;
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
- dd->dd_uid = stat_buf.st_uid;
|
|
|
3a204fb |
dd->dd_gid = stat_buf.st_gid;
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
|
|
|
3a204fb |
if ((flags & DD_OPEN_FD_ONLY))
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ dd->dd_md_fd = dd_open_meta_data_dir(dd);
|
|
|
3a204fb |
return dd;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
errno = 0;
|
|
|
3a204fb |
if (dd_lock(dd, WAIT_FOR_OTHER_PROCESS_USLEEP, flags) < 0)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- if ((flags & DD_OPEN_READONLY) && errno == EACCES)
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- /* Directory is not writable. If it seems to be readable,
|
|
|
3a204fb |
- * return "read only" dd, not NULL
|
|
|
3a204fb |
- *
|
|
|
3a204fb |
- * Does the directory have 'r' flag?
|
|
|
3a204fb |
- */
|
|
|
3a204fb |
- if (faccessat(dd->dd_fd, ".", R_OK, AT_SYMLINK_NOFOLLOW) == 0)
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- if(dd_check(dd) != NULL)
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- dd_close(dd);
|
|
|
3a204fb |
- dd = NULL;
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
- return dd;
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
if (errno == EISDIR)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
/* EISDIR: dd_lock can lock the dir, but it sees no time file there,
|
|
|
3a204fb |
@@ -504,26 +785,56 @@ static struct dump_dir *dd_do_open(struct dump_dir *dd, const char *dir, int fla
|
|
|
3a204fb |
* defaults to "."!
|
|
|
3a204fb |
*/
|
|
|
3a204fb |
error_msg("'%s' is not a problem directory", dd->dd_dirname);
|
|
|
3a204fb |
+ goto fail_with_close;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
- else
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (!(flags & DD_OPEN_READONLY))
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- cant_access:
|
|
|
3a204fb |
- if (errno == ENOENT || errno == ENOTDIR)
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- if (!(flags & DD_FAIL_QUIETLY_ENOENT))
|
|
|
3a204fb |
- error_msg("'%s' does not exist", dd->dd_dirname);
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
- else
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- if (!(flags & DD_FAIL_QUIETLY_EACCES))
|
|
|
3a204fb |
- perror_msg("Can't access '%s'", dd->dd_dirname);
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
+ log_debug("'%s' can't be opened for writing", dd->dd_dirname);
|
|
|
3a204fb |
+ goto fail_with_close;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
- dd_close(dd);
|
|
|
3a204fb |
- return NULL;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (errno != EACCES)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ VERB3 perror_msg("failed to lock dump directory '%s'", dd->dd_dirname);
|
|
|
3a204fb |
+ goto fail_with_close;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* Directory is not writable. If it seems to be readable,
|
|
|
3a204fb |
+ * return "read only" dd, not NULL
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * Does the directory have 'r' flag?
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+ if (faccessat(dd->dd_fd, ".", R_OK, AT_SYMLINK_NOFOLLOW) != 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ VERB3 perror_msg("failed to lock dump directory '%s'", dd->dd_dirname);
|
|
|
3a204fb |
+ goto fail_with_close;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* dd_check prints out good log messages */
|
|
|
3a204fb |
+ if(dd_check(dd) != NULL)
|
|
|
3a204fb |
+ goto fail_with_close;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* The dd is opened in READONLY moded, continue.*/
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
return dd;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+cant_access:
|
|
|
3a204fb |
+ if (errno == ENOENT || errno == ENOTDIR)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ if (!(flags & DD_FAIL_QUIETLY_ENOENT))
|
|
|
3a204fb |
+ error_msg("'%s' does not exist", dd->dd_dirname);
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ else
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ if (!(flags & DD_FAIL_QUIETLY_EACCES))
|
|
|
3a204fb |
+ perror_msg("Can't access '%s'", dd->dd_dirname);
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+fail_with_close:
|
|
|
3a204fb |
+ dd_close(dd);
|
|
|
3a204fb |
+ return NULL;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
struct dump_dir *dd_fdopendir(struct dump_dir *dd, int flags)
|
|
|
3a204fb |
@@ -607,8 +918,7 @@ struct dump_dir *dd_opendir(const char *dir, int flags)
|
|
|
3a204fb |
*/
|
|
|
3a204fb |
struct dump_dir *dd_create_skeleton(const char *dir, uid_t uid, mode_t mode, int flags)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- /* a little trick to copy read bits from file mode to exec bit of dir mode*/
|
|
|
3a204fb |
- mode_t dir_mode = mode | ((mode & 0444) >> 2);
|
|
|
3a204fb |
+ mode_t dir_mode = DD_MODE_TO_DIR_MODE(mode);
|
|
|
3a204fb |
struct dump_dir *dd = dd_init();
|
|
|
3a204fb |
|
|
|
3a204fb |
dd->mode = mode;
|
|
|
3a204fb |
@@ -673,8 +983,25 @@ struct dump_dir *dd_create_skeleton(const char *dir, uid_t uid, mode_t mode, int
|
|
|
3a204fb |
goto fail;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
- dd->dd_uid = (uid_t)-1L;
|
|
|
3a204fb |
- dd->dd_gid = (gid_t)-1L;
|
|
|
3a204fb |
+ /* Initiliaze dd_uid and dd_gid to sane values which reflect the reality.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+ dd->dd_uid = stat_sb.st_uid;
|
|
|
3a204fb |
+ dd->dd_gid = stat_sb.st_gid;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* Create META-DATA directory with real fs attributes which must be changed
|
|
|
3a204fb |
+ * in dd_reset_ownership(), when populating of a new dump directory is
|
|
|
3a204fb |
+ * done.
|
|
|
3a204fb |
+ *
|
|
|
3a204fb |
+ * It allows daemons to create a dump directory, populate the directory as
|
|
|
3a204fb |
+ * root and then switch the ownership to the real user.
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+ dd->dd_md_fd = dd_create_subdir(dd->dd_fd, META_DATA_DIR_NAME, dd->dd_uid, dd->dd_gid, dir_mode);
|
|
|
3a204fb |
+ if (dd->dd_md_fd < 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ error_msg("Can't create meta-data directory");
|
|
|
3a204fb |
+ goto fail;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
if (uid != (uid_t)-1L)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
dd->dd_uid = 0;
|
|
|
3a204fb |
@@ -726,12 +1053,16 @@ int dd_reset_ownership(struct dump_dir *dd)
|
|
|
3a204fb |
if (!dd->locked)
|
|
|
3a204fb |
error_msg_and_die("dump_dir is not opened"); /* bug */
|
|
|
3a204fb |
|
|
|
3a204fb |
- const int r = fchown(dd->dd_fd, dd->dd_uid, dd->dd_gid);
|
|
|
3a204fb |
+ int r = fchown(dd->dd_fd, dd->dd_uid, dd->dd_gid);
|
|
|
3a204fb |
if (r < 0)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
perror_msg("Can't change '%s' ownership to %lu:%lu", dd->dd_dirname,
|
|
|
3a204fb |
(long)dd->dd_uid, (long)dd->dd_gid);
|
|
|
3a204fb |
}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (dd_chown_meta_data(dd, dd->dd_uid, dd->dd_gid) != 0)
|
|
|
3a204fb |
+ error_msg("Failed to reset ownership of meta-data");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
return r;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
@@ -864,27 +1195,27 @@ void dd_sanitize_mode_and_owner(struct dump_dir *dd)
|
|
|
3a204fb |
next:
|
|
|
3a204fb |
free(short_name);
|
|
|
3a204fb |
}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* No need to check return value, the functions print good messages.
|
|
|
3a204fb |
+ * There are two approaches for handling errors in libreport:
|
|
|
3a204fb |
+ * - print out a warning message and keep status quo
|
|
|
3a204fb |
+ * - terminate the process
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+ dd_sanitize_mode_meta_data(dd);
|
|
|
3a204fb |
+ dd_chown_meta_data(dd, dd->dd_uid, dd->dd_gid);
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
static int delete_file_dir(int dir_fd, bool skip_lock_file)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- int opendir_fd = dup(dir_fd);
|
|
|
3a204fb |
- if (opendir_fd < 0)
|
|
|
3a204fb |
+ DIR *d;
|
|
|
3a204fb |
+ int ret = fdreopen(dir_fd, &d);
|
|
|
3a204fb |
+ if (ret < 0)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- perror_msg("delete_file_dir: dup(dir_fd)");
|
|
|
3a204fb |
- return -1;
|
|
|
3a204fb |
- }
|
|
|
3a204fb |
-
|
|
|
3a204fb |
- lseek(opendir_fd, SEEK_SET, 0);
|
|
|
3a204fb |
- DIR *d = fdopendir(opendir_fd);
|
|
|
3a204fb |
- if (!d)
|
|
|
3a204fb |
- {
|
|
|
3a204fb |
- close(opendir_fd);
|
|
|
3a204fb |
/* The caller expects us to error out only if the directory
|
|
|
3a204fb |
* still exists (not deleted). If directory
|
|
|
3a204fb |
* *doesn't exist*, return 0 and clear errno.
|
|
|
3a204fb |
*/
|
|
|
3a204fb |
- if (errno == ENOENT || errno == ENOTDIR)
|
|
|
3a204fb |
+ if (ret == -ENOENT || ret == -ENOTDIR)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
errno = 0;
|
|
|
3a204fb |
return 0;
|
|
|
3a204fb |
@@ -946,6 +1277,35 @@ static int delete_file_dir(int dir_fd, bool skip_lock_file)
|
|
|
3a204fb |
return 0;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
+static int dd_delete_meta_data(struct dump_dir *dd)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ if (!dd->locked)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ error_msg("Can't remove meta-data of unlocked problem directory %s", dd->dd_dirname);
|
|
|
3a204fb |
+ return -1;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ int dd_md_fd = dd_get_meta_data_dir_fd(dd, /*no create*/0);
|
|
|
3a204fb |
+ if (dd_md_fd < 0)
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (delete_file_dir(dd_md_fd, /*skip_lock_file:*/ true) != 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Can't remove meta-data from '"META_DATA_DIR_NAME"'");
|
|
|
3a204fb |
+ return -2;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ dd_close_meta_data_dir(dd);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (unlinkat(dd->dd_fd, META_DATA_DIR_NAME, AT_REMOVEDIR))
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ perror_msg("Can't remove meta-data directory '"META_DATA_DIR_NAME"'");
|
|
|
3a204fb |
+ return -3;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
int dd_delete(struct dump_dir *dd)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
if (!dd->locked)
|
|
|
3a204fb |
@@ -954,6 +1314,9 @@ int dd_delete(struct dump_dir *dd)
|
|
|
3a204fb |
return -1;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
+ if (dd_delete_meta_data(dd) != 0)
|
|
|
3a204fb |
+ return -2;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
if (delete_file_dir(dd->dd_fd, /*skip_lock_file:*/ true) != 0)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
perror_msg("Can't remove contents of directory '%s'", dd->dd_dirname);
|
|
|
3a204fb |
@@ -1029,7 +1392,10 @@ int dd_chown(struct dump_dir *dd, uid_t new_uid)
|
|
|
3a204fb |
|
|
|
3a204fb |
chown_res = fchown(fd, owners_uid, groups_gid);
|
|
|
3a204fb |
if (chown_res)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
perror_msg("fchownat('%s')", short_name);
|
|
|
3a204fb |
+ break;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
|
|
|
3a204fb |
close(fd);
|
|
|
3a204fb |
next:
|
|
|
3a204fb |
@@ -1037,6 +1403,15 @@ next:
|
|
|
3a204fb |
}
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
+ if (chown_res == 0)
|
|
|
3a204fb |
+ chown_res = dd_chown_meta_data(dd, owners_uid, groups_gid);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (chown_res == 0)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ dd->dd_uid = owners_uid;
|
|
|
3a204fb |
+ dd->dd_gid = groups_gid;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
return chown_res;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
@@ -1175,7 +1550,7 @@ char* dd_load_text_ext(const struct dump_dir *dd, const char *name, unsigned fla
|
|
|
3a204fb |
// if (!dd->locked)
|
|
|
3a204fb |
// error_msg_and_die("dump_dir is not opened"); /* bug */
|
|
|
3a204fb |
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
{
|
|
|
3a204fb |
error_msg("Cannot load text. '%s' is not a valid file name", name);
|
|
|
3a204fb |
if ((flags & DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE))
|
|
|
3a204fb |
@@ -1201,7 +1576,7 @@ void dd_save_text(struct dump_dir *dd, const char *name, const char *data)
|
|
|
3a204fb |
if (!dd->locked)
|
|
|
3a204fb |
error_msg_and_die("dump_dir is not opened"); /* bug */
|
|
|
3a204fb |
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
error_msg_and_die("Cannot save text. '%s' is not a valid file name", name);
|
|
|
3a204fb |
|
|
|
3a204fb |
save_binary_file_at(dd->dd_fd, name, data, strlen(data), dd->dd_uid, dd->dd_gid, dd->mode);
|
|
|
3a204fb |
@@ -1212,7 +1587,7 @@ void dd_save_binary(struct dump_dir* dd, const char* name, const char* data, uns
|
|
|
3a204fb |
if (!dd->locked)
|
|
|
3a204fb |
error_msg_and_die("dump_dir is not opened"); /* bug */
|
|
|
3a204fb |
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
error_msg_and_die("Cannot save binary. '%s' is not a valid file name", name);
|
|
|
3a204fb |
|
|
|
3a204fb |
save_binary_file_at(dd->dd_fd, name, data, size, dd->dd_uid, dd->dd_gid, dd->mode);
|
|
|
3a204fb |
@@ -1220,7 +1595,7 @@ void dd_save_binary(struct dump_dir* dd, const char* name, const char* data, uns
|
|
|
3a204fb |
|
|
|
3a204fb |
long dd_get_item_size(struct dump_dir *dd, const char *name)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
error_msg_and_die("Cannot get item size. '%s' is not a valid file name", name);
|
|
|
3a204fb |
|
|
|
3a204fb |
long size = -1;
|
|
|
3a204fb |
@@ -1245,7 +1620,7 @@ int dd_delete_item(struct dump_dir *dd, const char *name)
|
|
|
3a204fb |
if (!dd->locked)
|
|
|
3a204fb |
error_msg_and_die("dump_dir is not opened"); /* bug */
|
|
|
3a204fb |
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
error_msg_and_die("Cannot delete item. '%s' is not a valid file name", name);
|
|
|
3a204fb |
|
|
|
3a204fb |
int res = unlinkat(dd->dd_fd, name, /*only files*/0);
|
|
|
3a204fb |
@@ -1483,7 +1858,7 @@ int dd_mark_as_notreportable(struct dump_dir *dd, const char *reason)
|
|
|
3a204fb |
|
|
|
3a204fb |
int dd_copy_file(struct dump_dir *dd, const char *name, const char *source_path)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
error_msg_and_die("Cannot test existence. '%s' is not a valid file name", name);
|
|
|
3a204fb |
|
|
|
3a204fb |
log_debug("copying '%s' to '%s' at '%s'", source_path, name, dd->dd_dirname);
|
|
|
3a204fb |
@@ -1502,7 +1877,7 @@ int dd_copy_file(struct dump_dir *dd, const char *name, const char *source_path)
|
|
|
3a204fb |
|
|
|
3a204fb |
int dd_copy_file_unpack(struct dump_dir *dd, const char *name, const char *source_path)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- if (!str_is_correct_filename(name))
|
|
|
3a204fb |
+ if (!dd_validate_element_name(name))
|
|
|
3a204fb |
error_msg_and_die("Cannot test existence. '%s' is not a valid file name", name);
|
|
|
3a204fb |
|
|
|
3a204fb |
log_debug("unpacking '%s' to '%s' at '%s'", source_path, name, dd->dd_dirname);
|
|
|
3a204fb |
diff --git a/tests/dump_dir.at b/tests/dump_dir.at
|
|
|
3a204fb |
index 31c320e..4bf479e 100644
|
|
|
3a204fb |
--- a/tests/dump_dir.at
|
|
|
3a204fb |
+++ b/tests/dump_dir.at
|
|
|
3a204fb |
@@ -158,6 +158,177 @@ int main(int argc, char **argv)
|
|
|
3a204fb |
}
|
|
|
3a204fb |
]])
|
|
|
3a204fb |
|
|
|
3a204fb |
+## --------------------- ##
|
|
|
3a204fb |
+## dd_create_open_delete ##
|
|
|
3a204fb |
+## --------------------- ##
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+AT_TESTFUN([dd_create_open_delete],
|
|
|
3a204fb |
+[[
|
|
|
3a204fb |
+#include "internal_libreport.h"
|
|
|
3a204fb |
+#include <errno.h>
|
|
|
3a204fb |
+#include <assert.h>
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+int main(int argc, char **argv)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ g_verbose = 3;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ char template[] = "/tmp/XXXXXX/dump_dir";
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ char *last_slash = strrchr(template, '/');
|
|
|
3a204fb |
+ *last_slash = '\0';
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (mkdtemp(template) == NULL) {
|
|
|
3a204fb |
+ perror("mkdtemp()");
|
|
|
3a204fb |
+ return EXIT_FAILURE;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ *last_slash = '/';
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ struct dump_dir *dd = dd_create(template, (uid_t)-1, 0640);
|
|
|
3a204fb |
+ assert(strcmp(dd->dd_dirname, template) == 0);
|
|
|
3a204fb |
+ assert(dd->dd_fd >= 0);
|
|
|
3a204fb |
+ assert(dd->dd_md_fd >= 0);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ struct stat dd_st;
|
|
|
3a204fb |
+ assert(fstat(dd->dd_fd, &dd_st) == 0);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ struct stat md_st;
|
|
|
3a204fb |
+ assert(fstat(dd->dd_md_fd, &md_st) == 0);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(dd_st.st_uid == md_st.st_uid);
|
|
|
3a204fb |
+ assert(dd_st.st_gid == md_st.st_gid);
|
|
|
3a204fb |
+ assert((dd_st.st_mode & 0666) == (md_st.st_mode & 0666));
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ struct stat path_md_st;
|
|
|
3a204fb |
+ assert(fstatat(dd->dd_fd, ".libreport", &path_md_st, 0) == 0);
|
|
|
3a204fb |
+ assert(md_st.st_ino = path_md_st.st_ino);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ dd_create_basic_files(dd, (uid_t)-1, NULL);
|
|
|
3a204fb |
+ dd_save_text(dd, FILENAME_TYPE, "attest");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ dd_close(dd);
|
|
|
3a204fb |
+ dd = NULL;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ dd = dd_opendir(template, 0);
|
|
|
3a204fb |
+ assert(dd != NULL);
|
|
|
3a204fb |
+ assert(strcmp(dd->dd_dirname, template) == 0);
|
|
|
3a204fb |
+ assert(dd->dd_fd >= 0);
|
|
|
3a204fb |
+ assert(dd->dd_md_fd < 0);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ dd_delete(dd);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(stat(template, &dd_st) != 0);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ *last_slash = '\0';
|
|
|
3a204fb |
+ assert(rmdir(template) == 0);
|
|
|
3a204fb |
+ return EXIT_SUCCESS;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+]])
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+## -------------------------- ##
|
|
|
3a204fb |
+## dd_sanitize_mode_and_owner ##
|
|
|
3a204fb |
+## -------------------------- ##
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+AT_TESTFUN([dd_sanitize_mode_and_owner],
|
|
|
3a204fb |
+[[
|
|
|
3a204fb |
+#include "internal_libreport.h"
|
|
|
3a204fb |
+#include <errno.h>
|
|
|
3a204fb |
+#include <assert.h>
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+int main(int argc, char **argv)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ g_verbose = 3;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ char template[] = "/tmp/XXXXXX/dump_dir";
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ char *last_slash = strrchr(template, '/');
|
|
|
3a204fb |
+ *last_slash = '\0';
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (mkdtemp(template) == NULL) {
|
|
|
3a204fb |
+ perror("mkdtemp()");
|
|
|
3a204fb |
+ return EXIT_FAILURE;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ *last_slash = '/';
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* Prepare a directory for chmod test, use mode 0600 and chmod it to 0640 */
|
|
|
3a204fb |
+ struct dump_dir *dd = dd_create(template, (uid_t)-1, 0600);
|
|
|
3a204fb |
+ assert(dd != NULL);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ struct stat path_md_st;
|
|
|
3a204fb |
+ assert((fstatat(dd->dd_fd, ".libreport", &path_md_st, 0) == 0) || !"Failed initialize meta-data");
|
|
|
3a204fb |
+ assert((path_md_st.st_mode & 0077) == 0);
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ dd_create_basic_files(dd, (uid_t)-1, NULL);
|
|
|
3a204fb |
+ dd_save_text(dd, FILENAME_TYPE, "attest");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ dd_close(dd);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* initialize meta-data */
|
|
|
3a204fb |
+ dd = dd_opendir(template, DD_OPEN_FD_ONLY);
|
|
|
3a204fb |
+ /* reopen for writing */
|
|
|
3a204fb |
+ dd = dd_fdopendir(dd, /*for writing*/0);
|
|
|
3a204fb |
+ assert(dd != NULL);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(fchmod(dd->dd_fd, 0750) == 0);
|
|
|
3a204fb |
+ dd->mode = 0640;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ fprintf(stderr, "Going to sanitize\n");
|
|
|
3a204fb |
+ dd_sanitize_mode_and_owner(dd);
|
|
|
3a204fb |
+ fprintf(stderr, "Sanitized\n");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ DIR *d = opendir(template);
|
|
|
3a204fb |
+ struct dirent *dent;
|
|
|
3a204fb |
+ while ((dent = readdir(d)) != NULL)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ if ( strcmp(".", dent->d_name) == 0
|
|
|
3a204fb |
+ || strcmp("..", dent->d_name) == 0
|
|
|
3a204fb |
+ || strcmp(".lock", dent->d_name) == 0
|
|
|
3a204fb |
+ || strcmp(".libreport", dent->d_name) == 0
|
|
|
3a204fb |
+ )
|
|
|
3a204fb |
+ continue;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ struct stat sb;
|
|
|
3a204fb |
+ printf("Testing element: %s\n", dent->d_name);
|
|
|
3a204fb |
+ assert(fstatat(dd->dd_fd, dent->d_name, &sb, 0) == 0 || !"Cannot stat a regular element");
|
|
|
3a204fb |
+ assert((sb.st_mode & 0777) == 0640 || !"Failed to chmod a regular element");
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+ closedir(d);
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ struct stat path_md_st;
|
|
|
3a204fb |
+ assert(fstatat(dd->dd_fd, ".libreport", &path_md_st, 0) == 0 || !"Cannot stat meta-data directory");
|
|
|
3a204fb |
+ assert((path_md_st.st_mode & 0777) == 0750 || !"Failed chmod meta-data");
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ int md_dir_fd = openat(dd->dd_fd, ".libreport", O_DIRECTORY);
|
|
|
3a204fb |
+ assert(md_dir_fd >= 0 || !"Cannot open meta-data directory");
|
|
|
3a204fb |
+ DIR *d = fdopendir(md_dir_fd);
|
|
|
3a204fb |
+ struct dirent *dent;
|
|
|
3a204fb |
+ while ((dent = readdir(d)) != NULL)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ if (strcmp(".", dent->d_name) == 0 || strcmp("..", dent->d_name) == 0)
|
|
|
3a204fb |
+ continue;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ struct stat sb;
|
|
|
3a204fb |
+ printf("Testing meta-data: %s\n", dent->d_name);
|
|
|
3a204fb |
+ assert(fstatat(md_dir_fd, dent->d_name, &sb, 0) == 0 || !"Cannot stat meta-data file");
|
|
|
3a204fb |
+ assert((sb.st_mode & 0777) == 0640 || !"Failed to chmod a meta-data file");
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ closedir(d);
|
|
|
3a204fb |
+ dd_delete(dd);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ *last_slash = '\0';
|
|
|
3a204fb |
+ assert(rmdir(template) == 0);
|
|
|
3a204fb |
+ return EXIT_SUCCESS;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+]])
|
|
|
3a204fb |
+
|
|
|
3a204fb |
## -------------- ##
|
|
|
3a204fb |
## recursive_lock ##
|
|
|
3a204fb |
## -------------- ##
|
|
|
3a204fb |
--
|
|
|
3a204fb |
2.1.0
|
|
|
3a204fb |
|