e_comp_wl_data: added mediator function between data source and offer clients. 80/269580/4
authorJunseok, Kim <juns.kim@samsung.com>
Tue, 18 Jan 2022 12:17:51 +0000 (21:17 +0900)
committerJunseok, Kim <juns.kim@samsung.com>
Wed, 26 Jan 2022 02:28:17 +0000 (11:28 +0900)
In Some system, FD passing is blocked by their security policy.
It could be cause block the IPC between data source and offer client, and it finally the DnD operation gones to fail.
To avoid this problem, added mediator to makes IPC structure being to client -> server -> client instead of direct IPC of client to client.

Change-Id: I12544ea4c8a26422461533d86399e620cec0c46f

src/bin/e_comp_wl_data.c
src/bin/e_comp_wl_data.h

index be3b7b72bca8bd2b515840db5dbb6a57a0008d02..7d2bcdf19fe566e26bf8330b53c4369da65a379c 100644 (file)
@@ -25,20 +25,92 @@ _e_comp_wl_data_offer_cb_accept(struct wl_client *client EINA_UNUSED, struct wl_
      offer->source->target(offer->source, serial, mime_type);
 }
 
+static Eina_Bool
+_e_comp_wl_dnd_offer_mediate(void *data, Ecore_Fd_Handler *handler)
+{
+   E_Comp_Wl_Data_Offer *offer;
+   char *p;
+   int read_len = 0, write_len = 0;
+   int source_fd = -1;
+
+   if (!(offer = (E_Comp_Wl_Data_Offer*)data))
+     return ECORE_CALLBACK_CANCEL;
+
+   source_fd = ecore_main_fd_handler_fd_get(handler);
+   if (source_fd < 0) goto cleanup;
+   if (offer->fd < 0) goto cleanup;
+
+   p = (char *)calloc(sizeof(char), CLIPBOARD_CHUNK);
+
+   while ((read_len = read(source_fd, p, CLIPBOARD_CHUNK)) > 0)
+     {
+        write_len = write(offer->fd, p, read_len);
+        if (read_len != write_len)
+        {
+           ERR("IO error in _e_comp_wl_dnd_offer_mediate");
+           break;
+        }
+     }
+
+cleanup:
+   if (offer->fd > 0)
+     {
+        close(offer->fd);
+        offer->fd = 0;
+     }
+   if (source_fd > 0) close(source_fd);
+   if (handler != NULL) ecore_main_fd_handler_del(handler);
+   if (p) free(p);
+
+   return ECORE_CALLBACK_DONE;
+}
+
+static int
+_e_comp_wl_dnd_offer_mediator_init(E_Comp_Wl_Data_Offer* offer, int fd)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(offer, -1);
+
+   if (pipe2(offer->source->fd, O_CLOEXEC|O_DIRECT|O_NONBLOCK) == -1)
+   {
+      ERR("Could not create unidirectional pipe for dnd: %m");
+      return -1;
+   }
+
+   offer->fd = fd;
+   offer->source->fd_handler =
+      ecore_main_fd_handler_add(offer->source->fd[0], ECORE_FD_READ,
+                                _e_comp_wl_dnd_offer_mediate, offer,
+                                NULL, NULL);
+
+   DBG("_e_comp_wl_dnd_offer_mediate:: init mediator, offer_fd: %d / source_fd: %d, %d", fd, offer->source->fd[0], offer->source->fd[1]);
+   return offer->source->fd[1];
+}
+
 static void
 _e_comp_wl_data_offer_cb_receive(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type, int32_t fd)
 {
    E_Comp_Wl_Data_Offer *offer;
+   int new_fd;
 
    DBG("Data Offer Receive FD:%d", fd);
 
    if (!(offer = wl_resource_get_user_data(resource)))
-     return;
+     {
+        close(fd);
+        return;
+     }
 
-   if (offer->source)
-     offer->source->send(offer->source, mime_type, fd);
+   new_fd = _e_comp_wl_dnd_offer_mediator_init(offer, fd);
+   if (new_fd < 0)
+     {
+        DBG("_e_comp_wl_dnd_offer_mediator_init failed, close fd:%d", fd);
+        close(fd);
+        return;
+     }
 
-   close(fd);
+   if (offer->source)
+     offer->source->send(offer->source, mime_type, new_fd);
+   close(new_fd);
 }
 
 /* called by wl_data_offer_destroy */
@@ -61,6 +133,7 @@ _e_comp_wl_data_offer_cb_resource_destroy(struct wl_resource *resource)
    if (offer->source)
      {
         wl_list_remove(&offer->source_destroy_listener.link);
+        ecore_main_fd_handler_del(offer->source->fd_handler);
         if (offer->dropped && offer->source != e_comp_wl->drag_source)
           _e_comp_wl_data_source_cancelled_send(offer->source);
      }
index 7b35e5a8fcfa9a3c9b640c90ffbd176e20eca2bd..864642a5804a95693bbb06b625024087df7cc493 100644 (file)
@@ -30,6 +30,8 @@ struct _E_Comp_Wl_Data_Source
    void (*cancelled) (E_Comp_Wl_Data_Source *source);
 
    Eina_Bool is_manual;
+   int fd[2];
+   Ecore_Fd_Handler *fd_handler;
 };
 
 struct _E_Comp_Wl_Data_Offer
@@ -40,6 +42,8 @@ struct _E_Comp_Wl_Data_Offer
 
    E_Comp_Wl_Data_Source *source; //indicates source client data
    struct wl_listener source_destroy_listener; //listener for destroy of source
+
+   int fd;
 };
 
 struct _E_Comp_Wl_Clipboard_Source