summaryrefslogtreecommitdiff
path: root/document-portal
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2020-02-28 09:16:31 +0100
committerAlexander Larsson <alexl@redhat.com>2020-03-05 13:48:25 +0100
commit516e171bb0489e1803894d4ec1a422002bf9972d (patch)
treeba36bbbfa569135c8c292cb5af80ddc3acebc8cc /document-portal
parent25d5d930f90521e371c923a2bce261960c229a9f (diff)
document-portal: Support new DOCUMENT_ADD_FLAGS_DIRECTORY in AddFull
For directoy entries the DOCUMENT_ENTRY_FLAG_DIRECTORY flag is set in the document store for the entry. Also, in the directory case we store the device/inode of the directory itself, not the parent.
Diffstat (limited to 'document-portal')
-rw-r--r--document-portal/document-enums.h3
-rw-r--r--document-portal/document-portal.c99
-rw-r--r--document-portal/document-portal.h1
-rw-r--r--document-portal/document-store.h1
-rw-r--r--document-portal/file-transfer.c2
5 files changed, 65 insertions, 41 deletions
diff --git a/document-portal/document-enums.h b/document-portal/document-enums.h
index 8ac37a4..d126ecc 100644
--- a/document-portal/document-enums.h
+++ b/document-portal/document-enums.h
@@ -16,8 +16,9 @@ typedef enum {
DOCUMENT_ADD_FLAGS_REUSE_EXISTING = (1 << 0),
DOCUMENT_ADD_FLAGS_PERSISTENT = (1 << 1),
DOCUMENT_ADD_FLAGS_AS_NEEDED_BY_APP = (1 << 2),
+ DOCUMENT_ADD_FLAGS_DIRECTORY = (1 << 3),
- DOCUMENT_ADD_FLAGS_FLAGS_ALL = ((1 << 3) - 1)
+ DOCUMENT_ADD_FLAGS_FLAGS_ALL = ((1 << 4) - 1)
} DocumentAddFullFlags;
G_END_DECLS
diff --git a/document-portal/document-portal.c b/document-portal/document-portal.c
index 8197270..6a56ad6 100644
--- a/document-portal/document-portal.c
+++ b/document-portal/document-portal.c
@@ -286,7 +286,7 @@ portal_delete (GDBusMethodInvocation *invocation,
}
static char *
-do_create_doc (struct stat *parent_st_buf, const char *path, gboolean reuse_existing, gboolean persistent)
+do_create_doc (struct stat *parent_st_buf, const char *path, gboolean reuse_existing, gboolean persistent, gboolean directory)
{
g_autoptr(GVariant) data = NULL;
g_autoptr(PermissionDbEntry) entry = NULL;
@@ -294,12 +294,14 @@ do_create_doc (struct stat *parent_st_buf, const char *path, gboolean reuse_exis
char *id = NULL;
guint32 flags = 0;
- g_debug ("Creating document at path '%s', resuse_existing: %d, persistent: %d", path, reuse_existing, persistent);
+ g_debug ("Creating document at path '%s', resuse_existing: %d, persistent: %d, directory: %d", path, reuse_existing, persistent, directory);
if (!reuse_existing)
flags |= DOCUMENT_ENTRY_FLAG_UNIQUE;
if (!persistent)
flags |= DOCUMENT_ENTRY_FLAG_TRANSIENT;
+ if (directory)
+ flags |= DOCUMENT_ENTRY_FLAG_DIRECTORY;
data =
g_variant_ref_sink (g_variant_new ("(^ayttu)",
path,
@@ -348,8 +350,9 @@ do_create_doc (struct stat *parent_st_buf, const char *path, gboolean reuse_exis
gboolean
validate_fd (int fd,
XdpAppInfo *app_info,
+ gboolean is_directory,
struct stat *st_buf,
- struct stat *real_parent_st_buf,
+ struct stat *real_dir_st_buf,
char **path_out,
gboolean *writable_out,
GError **error)
@@ -360,41 +363,54 @@ validate_fd (int fd,
xdp_autofd int dir_fd = -1;
struct stat real_st_buf;
- path = xdp_app_info_get_path_for_fd (app_info, fd, S_IFREG, st_buf, writable_out);
+ path = xdp_app_info_get_path_for_fd (app_info, fd, 0, st_buf, writable_out);
if (path == NULL)
+ goto errout;
+
+ if (!is_directory && S_ISREG (st_buf->st_mode))
{
- /* Don't leak any info about real file path existence, etc */
- g_set_error (error,
- XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
- "Invalid fd passed");
- return FALSE;
+ /* We open the parent directory and do the stat in that, so that we have
+ * trustworthy parent dev/ino + filename for later verification. Otherwise the caller
+ * could later replace a parent with a symlink and make us read some other file.
+ */
+ dirname = g_path_get_dirname (path);
+ name = g_path_get_basename (path);
+ }
+ else if (is_directory && S_ISDIR (st_buf->st_mode))
+ {
+ /* For dirs, we keep the dev/ino of the directory itself */
+ dirname = g_strdup (path);
}
+ else
+ goto errout;
- /* We open the parent directory and do the stat in that, so that we have
- * trustworthy parent dev/ino + filename for later verification. Otherwise the caller
- * could later replace a parent with a symlink and make us read some other file.
- */
- dirname = g_path_get_dirname (path);
- name = g_path_get_basename (path);
dir_fd = open (dirname, O_CLOEXEC | O_PATH);
+ if (dir_fd < 0 || fstat (dir_fd, real_dir_st_buf) != 0)
+ goto errout;
- if (dir_fd < 0 ||
- fstat (dir_fd, real_parent_st_buf) < 0 ||
- fstatat (dir_fd, name, &real_st_buf, AT_SYMLINK_NOFOLLOW) < 0 ||
- st_buf->st_dev != real_st_buf.st_dev ||
- st_buf->st_ino != real_st_buf.st_ino)
+ if (name != NULL)
{
- /* Don't leak any info about real file path existence, etc */
- g_set_error (error,
- XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
- "Invalid fd passed");
- return FALSE;
+ if (fstatat (dir_fd, name, &real_st_buf, AT_SYMLINK_NOFOLLOW) < 0 ||
+ st_buf->st_dev != real_st_buf.st_dev ||
+ st_buf->st_ino != real_st_buf.st_ino)
+ goto errout;
}
+ else if (st_buf->st_dev != real_dir_st_buf->st_dev ||
+ st_buf->st_ino != real_dir_st_buf->st_ino)
+ goto errout;
+
if (path_out)
*path_out = g_steal_pointer (&path);
return TRUE;
+
+ errout:
+ /* Don't leak any info about real file path existence, etc */
+ g_set_error (error,
+ XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
+ "Invalid fd passed");
+ return FALSE;
}
static char *
@@ -727,8 +743,8 @@ document_add_full (int *fd,
const char *app_id = xdp_app_info_get_id (app_info);
g_autoptr(GPtrArray) ids = g_ptr_array_new_with_free_func (g_free);
g_autoptr(GPtrArray) paths = g_ptr_array_new_with_free_func (g_free);
- gboolean reuse_existing, persistent, as_needed_by_app, allow_write;
- g_autofree struct stat *real_parent_st_bufs = NULL;
+ gboolean reuse_existing, persistent, as_needed_by_app, allow_write, is_dir;
+ g_autofree struct stat *real_dir_st_bufs = NULL;
struct stat st_buf;
g_autofree gboolean *writable = NULL;
int i;
@@ -737,24 +753,25 @@ document_add_full (int *fd,
reuse_existing = (flags & DOCUMENT_ADD_FLAGS_REUSE_EXISTING) != 0;
persistent = (flags & DOCUMENT_ADD_FLAGS_PERSISTENT) != 0;
as_needed_by_app = (flags & DOCUMENT_ADD_FLAGS_AS_NEEDED_BY_APP) != 0;
+ is_dir = (flags & DOCUMENT_ADD_FLAGS_DIRECTORY) != 0;
allow_write = (target_perms & DOCUMENT_PERMISSION_FLAGS_WRITE) != 0;
g_ptr_array_set_size (paths, n_args + 1);
g_ptr_array_set_size (ids, n_args + 1);
- real_parent_st_bufs = g_new0 (struct stat, n_args);
+ real_dir_st_bufs = g_new0 (struct stat, n_args);
writable = g_new0 (gboolean, n_args);
for (i = 0; i < n_args; i++)
{
g_autofree char *path = NULL;
- if (!validate_fd (fd[i], app_info, &st_buf, &real_parent_st_bufs[i], &path, &writable[i], error))
+ if (!validate_fd (fd[i], app_info, is_dir, &st_buf, &real_dir_st_bufs[i], &path, &writable[i], error))
return NULL;
if (parent_dev != NULL && parent_ino != NULL)
{
- if (real_parent_st_bufs[i].st_dev != parent_dev[i] ||
- real_parent_st_bufs[i].st_ino != parent_ino[i])
+ if (real_dir_st_bufs[i].st_dev != parent_dev[i] ||
+ real_dir_st_bufs[i].st_ino != parent_ino[i])
{
g_set_error (error,
XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_NOT_ALLOWED,
@@ -776,6 +793,7 @@ document_add_full (int *fd,
if (st_buf.st_dev == fuse_dev)
{
/* The passed in fd is on the fuse filesystem itself */
+ /* TODO: This reuse code is not right for directory exposes (i.e. which file in there?) */
id = verify_existing_document (&st_buf, reuse_existing);
if (id == NULL)
{
@@ -814,7 +832,7 @@ document_add_full (int *fd,
if (g_ptr_array_index(ids,i) == NULL)
{
- id = do_create_doc (&real_parent_st_bufs[i], path, reuse_existing, persistent);
+ id = do_create_doc (&real_dir_st_bufs[i], path, reuse_existing, persistent, is_dir);
g_ptr_array_index(ids,i) = id;
if (app_id[0] != '\0' && strcmp (app_id, target_app_id) != 0)
@@ -894,7 +912,9 @@ portal_add_named_full (GDBusMethodInvocation *invocation,
return;
}
- if ((flags & ~DOCUMENT_ADD_FLAGS_FLAGS_ALL) != 0)
+ if ((flags & ~DOCUMENT_ADD_FLAGS_FLAGS_ALL) != 0 ||
+ /* Don't support directory named documents */
+ (flags & DOCUMENT_ADD_FLAGS_DIRECTORY) != 0)
{
g_dbus_method_invocation_return_error (invocation,
XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
@@ -965,7 +985,7 @@ portal_add_named_full (GDBusMethodInvocation *invocation,
}
else
{
- id = do_create_doc (&parent_st_buf, path, reuse_existing, persistent);
+ id = do_create_doc (&parent_st_buf, path, reuse_existing, persistent, FALSE);
if (app_id[0] != '\0' && strcmp (app_id, target_app_id) != 0)
{
@@ -1066,7 +1086,7 @@ portal_add_named (GDBusMethodInvocation *invocation,
XDP_AUTOLOCK (db);
- id = do_create_doc (&parent_st_buf, path, reuse_existing, persistent);
+ id = do_create_doc (&parent_st_buf, path, reuse_existing, persistent, FALSE);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)", id));
@@ -1116,7 +1136,7 @@ portal_lookup (GDBusMethodInvocation *invocation,
const char *filename;
g_autofree char *path = NULL;
xdp_autofd int fd = -1;
- struct stat st_buf, real_parent_st_buf;
+ struct stat st_buf, real_dir_st_buf;
g_auto(GStrv) ids = NULL;
g_autofree char *id = NULL;
GError *error = NULL;
@@ -1141,7 +1161,7 @@ portal_lookup (GDBusMethodInvocation *invocation,
return TRUE;
}
- if (!validate_fd (fd, app_info, &st_buf, &real_parent_st_buf, &path, NULL, &error))
+ if (!validate_fd (fd, app_info, FALSE, &st_buf, &real_dir_st_buf, &path, NULL, &error))
{
g_dbus_method_invocation_take_error (invocation, error);
return TRUE;
@@ -1151,6 +1171,7 @@ portal_lookup (GDBusMethodInvocation *invocation,
{
/* The passed in fd is on the fuse filesystem itself */
id = xdp_fuse_lookup_id_for_inode (st_buf.st_ino);
+ /* TODO: Handle directory documents here */
g_debug ("path on fuse, id %s", id);
}
else
@@ -1159,8 +1180,8 @@ portal_lookup (GDBusMethodInvocation *invocation,
data = g_variant_ref_sink (g_variant_new ("(^ayttu)",
path,
- (guint64)real_parent_st_buf.st_dev,
- (guint64)real_parent_st_buf.st_ino,
+ (guint64)real_dir_st_buf.st_dev,
+ (guint64)real_dir_st_buf.st_ino,
0));
ids = permission_db_list_ids_by_value (db, data);
if (ids[0] != NULL)
diff --git a/document-portal/document-portal.h b/document-portal/document-portal.h
index 26159a5..079cb37 100644
--- a/document-portal/document-portal.h
+++ b/document-portal/document-portal.h
@@ -25,6 +25,7 @@
gboolean validate_fd (int fd,
XdpAppInfo *app_info,
+ gboolean is_directory,
struct stat *st_buf,
struct stat *real_parent_st_buf,
char **path_out,
diff --git a/document-portal/document-store.h b/document-portal/document-store.h
index 1d4a15d..5af5d7e 100644
--- a/document-portal/document-store.h
+++ b/document-portal/document-store.h
@@ -9,6 +9,7 @@ G_BEGIN_DECLS
#define DOCUMENT_ENTRY_FLAG_UNIQUE (1 << 0)
#define DOCUMENT_ENTRY_FLAG_TRANSIENT (1 << 1)
+#define DOCUMENT_ENTRY_FLAG_DIRECTORY (1 << 2)
const char ** xdg_unparse_permissions (DocumentPermissionFlags permissions);
DocumentPermissionFlags xdp_parse_permissions (const char **permissions,
diff --git a/document-portal/file-transfer.c b/document-portal/file-transfer.c
index 73c73f5..eaf96aa 100644
--- a/document-portal/file-transfer.c
+++ b/document-portal/file-transfer.c
@@ -417,7 +417,7 @@ add_files (GDBusMethodInvocation *invocation,
return;
}
- if (!validate_fd (fd, app_info, &st_buf, &parent_st_buf, &path, &fd_is_writable, NULL) ||
+ if (!validate_fd (fd, app_info, FALSE, &st_buf, &parent_st_buf, &path, &fd_is_writable, NULL) ||
(transfer->writable && !fd_is_writable))
{
g_dbus_method_invocation_return_error (invocation,