1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22 
23 #include <config.h>
24 
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/errno.h>
28 #include <errno.h>
29 #include <sys/un.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdlib.h>
33 
34 #include <glib.h>
35 #include <glib/gi18n.h>
36 #include <glib/gstdio.h>
37 #include <glib-object.h>
38 #include <gvfsdaemon.h>
39 #include <gvfsdaemonprotocol.h>
40 #include <gvfsdaemonutils.h>
41 #include <gvfsutils.h>
42 #include <gvfsjobmount.h>
43 #include <gvfsjobopenforread.h>
44 #include <gvfsjobopenforwrite.h>
45 #include <gvfsjobunmount.h>
46 #include <gvfsmonitorimpl.h>
47 
48 enum {
49   PROP_0
50 };
51 
52 enum {
53   SHUTDOWN,
54   LAST_SIGNAL
55 };
56 
57 typedef struct {
58   char *obj_path;
59   GVfsRegisterPathCallback callback;
60   gpointer data;
61   GDBusInterfaceSkeleton *session_skeleton;
62   GHashTable *client_skeletons;
63 } RegisteredPath;
64 
65 struct _GVfsDaemon
66 {
67   GObject parent_instance;
68 
69   GMutex lock;
70   gboolean main_daemon;
71 
72   GThreadPool *thread_pool;
73   GHashTable *registered_paths;
74   GHashTable *client_connections;
75   GList *jobs;
76   GList *job_sources;
77 
78   guint exit_tag;
79 
80   gint mount_counter;
81 
82   GDBusAuthObserver *auth_observer;
83   GDBusConnection *conn;
84   GVfsDBusDaemon *daemon_skeleton;
85   GVfsDBusMountable *mountable_skeleton;
86   guint name_watcher;
87   gboolean lost_main_daemon;
88 };
89 
90 typedef struct {
91   GVfsDaemon *daemon;
92   char *socket_dir;
93   GDBusServer *server;
94 
95   GDBusConnection *conn;
96 } NewConnectionData;
97 
98 static guint signals[LAST_SIGNAL] = { 0 };
99 
100 static void              g_vfs_daemon_get_property (GObject        *object,
101 						    guint           prop_id,
102 						    GValue         *value,
103 						    GParamSpec     *pspec);
104 static void              g_vfs_daemon_set_property (GObject        *object,
105 						    guint           prop_id,
106 						    const GValue   *value,
107 						    GParamSpec     *pspec);
108 
109 static gboolean          handle_get_connection     (GVfsDBusDaemon        *object,
110                                                     GDBusMethodInvocation *invocation,
111                                                     gpointer               user_data);
112 static gboolean          handle_cancel             (GVfsDBusDaemon        *object,
113                                                     GDBusMethodInvocation *invocation,
114                                                     guint                  arg_serial,
115                                                     gpointer               user_data);
116 static gboolean          handle_list_monitor_implementations (GVfsDBusDaemon        *object,
117                                                     GDBusMethodInvocation *invocation,
118                                                     gpointer               user_data);
119 static gboolean          daemon_handle_mount       (GVfsDBusMountable     *object,
120                                                     GDBusMethodInvocation *invocation,
121                                                     GVariant              *arg_mount_spec,
122                                                     gboolean               arg_automount,
123                                                     GVariant              *arg_mount_source,
124                                                     gpointer               user_data);
125 static void              g_vfs_daemon_re_register_job_sources (GVfsDaemon *daemon);
126 
127 
128 
129 
130 
131 
G_DEFINE_TYPE(GVfsDaemon,g_vfs_daemon,G_TYPE_OBJECT)132 G_DEFINE_TYPE (GVfsDaemon, g_vfs_daemon, G_TYPE_OBJECT)
133 
134 static void
135 registered_path_free (RegisteredPath *data)
136 {
137   g_free (data->obj_path);
138   if (data->session_skeleton)
139     {
140       /* Unexport the interface skeleton on session bus */
141       g_dbus_interface_skeleton_unexport (data->session_skeleton);
142       g_object_unref (data->session_skeleton);
143     }
144   g_hash_table_destroy (data->client_skeletons);
145 
146   g_free (data);
147 }
148 
149 static void
g_vfs_daemon_finalize(GObject * object)150 g_vfs_daemon_finalize (GObject *object)
151 {
152   GVfsDaemon *daemon;
153 
154   daemon = G_VFS_DAEMON (object);
155 
156   /* There may be some jobs outstanding if we've been force unmounted. */
157   if (daemon->jobs)
158     g_warning ("daemon->jobs != NULL when finalizing daemon!");
159 
160   if (daemon->name_watcher)
161     g_bus_unwatch_name (daemon->name_watcher);
162 
163   if (daemon->daemon_skeleton != NULL)
164     {
165       g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (daemon->daemon_skeleton));
166       g_object_unref (daemon->daemon_skeleton);
167     }
168   if (daemon->mountable_skeleton != NULL)
169     {
170       g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (daemon->mountable_skeleton));
171       g_object_unref (daemon->mountable_skeleton);
172     }
173   if (daemon->conn != NULL)
174     g_object_unref (daemon->conn);
175   if (daemon->auth_observer != NULL)
176     g_object_unref (daemon->auth_observer);
177 
178   g_hash_table_destroy (daemon->registered_paths);
179   g_hash_table_destroy (daemon->client_connections);
180   g_mutex_clear (&daemon->lock);
181 
182   if (G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize)
183     (*G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize) (object);
184 }
185 
186 static void
g_vfs_daemon_class_init(GVfsDaemonClass * klass)187 g_vfs_daemon_class_init (GVfsDaemonClass *klass)
188 {
189   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
190 
191   gobject_class->finalize = g_vfs_daemon_finalize;
192   gobject_class->set_property = g_vfs_daemon_set_property;
193   gobject_class->get_property = g_vfs_daemon_get_property;
194 
195   signals[SHUTDOWN] =
196     g_signal_new ("shutdown",
197 		  G_TYPE_FROM_CLASS (gobject_class),
198 		  G_SIGNAL_RUN_LAST,
199 		  G_STRUCT_OFFSET (GVfsDaemonClass, shutdown),
200 		  NULL, NULL,
201 		  g_cclosure_marshal_VOID__VOID,
202 		  G_TYPE_NONE, 0);
203 }
204 
205 static void
job_handler_callback(gpointer data,gpointer user_data)206 job_handler_callback (gpointer       data,
207 		      gpointer       user_data)
208 {
209   GVfsJob *job = G_VFS_JOB (data);
210 
211   g_vfs_job_run (job);
212 }
213 
214 static void
name_appeared_handler(GDBusConnection * connection,const gchar * name,const gchar * name_owner,gpointer user_data)215 name_appeared_handler (GDBusConnection *connection,
216                        const gchar *name,
217                        const gchar *name_owner,
218                        gpointer user_data)
219 {
220   GVfsDaemon *daemon = G_VFS_DAEMON (user_data);
221 
222   if (strcmp (name, G_VFS_DBUS_DAEMON_NAME) == 0 &&
223       *name_owner != 0 &&
224       daemon->lost_main_daemon)
225       {
226         /* There is a new owner. Register mounts with it */
227         g_vfs_daemon_re_register_job_sources (daemon);
228       }
229 }
230 
231 static void
name_vanished_handler(GDBusConnection * connection,const gchar * name,gpointer user_data)232 name_vanished_handler (GDBusConnection *connection,
233                        const gchar *name,
234                        gpointer user_data)
235 {
236   GVfsDaemon *daemon = G_VFS_DAEMON (user_data);
237 
238   /* Ensure we react only to really lost daemon */
239   daemon->lost_main_daemon = TRUE;
240 }
241 
242 /*
243  * Authentication observer signal handler that rejects all authentication
244  * mechanisms except for EXTERNAL (credentials-passing), which is the
245  * recommended authentication mechanism for AF_UNIX sockets.
246  */
247 static gboolean
allow_mechanism_cb(GDBusAuthObserver * observer,const gchar * mechanism,G_GNUC_UNUSED gpointer user_data)248 allow_mechanism_cb (GDBusAuthObserver *observer,
249                     const gchar *mechanism,
250                     G_GNUC_UNUSED gpointer user_data)
251 {
252   if (g_strcmp0 (mechanism, "EXTERNAL") == 0)
253     return TRUE;
254 
255   return FALSE;
256 }
257 
258 /*
259  * Authentication observer signal handler that authorizes connections
260  * from the same uid as this process. This matches the behaviour of a
261  * libdbus DBusServer/DBusConnection when no DBusAllowUnixUserFunction
262  * has been set, but is not the default in GDBus.
263  */
264 static gboolean
authorize_authenticated_peer_cb(GDBusAuthObserver * observer,G_GNUC_UNUSED GIOStream * stream,GCredentials * credentials,G_GNUC_UNUSED gpointer user_data)265 authorize_authenticated_peer_cb (GDBusAuthObserver *observer,
266                                  G_GNUC_UNUSED GIOStream *stream,
267                                  GCredentials *credentials,
268                                  G_GNUC_UNUSED gpointer user_data)
269 {
270   gboolean authorized = FALSE;
271 
272   if (credentials != NULL)
273     {
274       GCredentials *own_credentials;
275 
276       own_credentials = g_credentials_new ();
277 
278       if (g_credentials_is_same_user (credentials, own_credentials, NULL))
279         authorized = TRUE;
280 
281       g_object_unref (own_credentials);
282     }
283 
284   return authorized;
285 }
286 
287 static void
g_vfs_daemon_init(GVfsDaemon * daemon)288 g_vfs_daemon_init (GVfsDaemon *daemon)
289 {
290   GError *error;
291   gint max_threads = 1; /* TODO: handle max threads */
292 
293   daemon->thread_pool = g_thread_pool_new (job_handler_callback,
294 					   daemon,
295 					   max_threads,
296 					   FALSE, NULL);
297   /* TODO: verify thread_pool != NULL in a nicer way */
298   g_assert (daemon->thread_pool != NULL);
299 
300   g_mutex_init (&daemon->lock);
301 
302   daemon->mount_counter = 0;
303 
304   daemon->jobs = NULL;
305   daemon->registered_paths =
306     g_hash_table_new_full (g_str_hash, g_str_equal,
307 			   g_free, (GDestroyNotify)registered_path_free);
308 
309   /* This is where we store active client connections so when a new filter is registered,
310    * we re-register them on all active connections */
311   daemon->client_connections =
312     g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
313 
314   daemon->conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
315   g_assert (daemon->conn != NULL);
316   daemon->auth_observer = g_dbus_auth_observer_new ();
317   g_signal_connect (daemon->auth_observer, "allow-mechanism", G_CALLBACK (allow_mechanism_cb), NULL);
318   g_signal_connect (daemon->auth_observer, "authorize-authenticated-peer", G_CALLBACK (authorize_authenticated_peer_cb), NULL);
319 
320   daemon->daemon_skeleton = gvfs_dbus_daemon_skeleton_new ();
321   g_signal_connect (daemon->daemon_skeleton, "handle-get-connection", G_CALLBACK (handle_get_connection), daemon);
322   g_signal_connect (daemon->daemon_skeleton, "handle-cancel", G_CALLBACK (handle_cancel), daemon);
323   g_signal_connect (daemon->daemon_skeleton, "handle-list-monitor-implementations", G_CALLBACK (handle_list_monitor_implementations), daemon);
324 
325   error = NULL;
326   if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (daemon->daemon_skeleton),
327                                          daemon->conn,
328                                          G_VFS_DBUS_DAEMON_PATH,
329                                          &error))
330     {
331       g_warning ("Error exporting daemon interface: %s (%s, %d)\n",
332                   error->message, g_quark_to_string (error->domain), error->code);
333       g_error_free (error);
334     }
335 
336   daemon->mountable_skeleton = gvfs_dbus_mountable_skeleton_new ();
337   g_signal_connect (daemon->mountable_skeleton, "handle-mount", G_CALLBACK (daemon_handle_mount), daemon);
338 
339   error = NULL;
340   if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (daemon->mountable_skeleton),
341       daemon->conn,
342                                          G_VFS_DBUS_MOUNTABLE_PATH,
343                                          &error))
344     {
345       g_warning ("Error exporting mountable interface: %s (%s, %d)\n",
346                   error->message, g_quark_to_string (error->domain), error->code);
347       g_error_free (error);
348     }
349 }
350 
351 static void
g_vfs_daemon_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)352 g_vfs_daemon_set_property (GObject         *object,
353 			   guint            prop_id,
354 			   const GValue    *value,
355 			   GParamSpec      *pspec)
356 {
357   switch (prop_id)
358     {
359     default:
360       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
361       break;
362     }
363 }
364 
365 static void
g_vfs_daemon_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)366 g_vfs_daemon_get_property (GObject    *object,
367 			   guint       prop_id,
368 			   GValue     *value,
369 			   GParamSpec *pspec)
370 {
371   switch (prop_id)
372     {
373     default:
374       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
375       break;
376     }
377 }
378 
379 GVfsDaemon *
g_vfs_daemon_new(gboolean main_daemon,gboolean replace)380 g_vfs_daemon_new (gboolean main_daemon, gboolean replace)
381 {
382   GVfsDaemon *daemon;
383   GDBusConnection *conn;
384   GError *error;
385 
386   error = NULL;
387   conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
388   if (!conn)
389     {
390       g_printerr ("Failed to connect to the D-BUS daemon: %s (%s, %d)\n",
391                   error->message, g_quark_to_string (error->domain), error->code);
392       g_error_free (error);
393       return NULL;
394     }
395 
396   daemon = g_object_new (G_VFS_TYPE_DAEMON, NULL);
397   daemon->main_daemon = main_daemon;
398 
399   if (! main_daemon)
400     {
401       daemon->name_watcher = g_bus_watch_name_on_connection (conn,
402                                                              G_VFS_DBUS_DAEMON_NAME,
403                                                              G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
404                                                              name_appeared_handler,
405                                                              name_vanished_handler,
406                                                              daemon,
407                                                              NULL);
408     }
409 
410   g_object_unref (conn);
411 
412   return daemon;
413 }
414 
415 void
g_vfs_daemon_set_max_threads(GVfsDaemon * daemon,gint max_threads)416 g_vfs_daemon_set_max_threads (GVfsDaemon                    *daemon,
417 			      gint                           max_threads)
418 {
419   g_thread_pool_set_max_threads (daemon->thread_pool, max_threads, NULL);
420 }
421 
422 static gboolean
exit_at_idle(GVfsDaemon * daemon)423 exit_at_idle (GVfsDaemon *daemon)
424 {
425   g_signal_emit (daemon, signals[SHUTDOWN], 0);
426   return FALSE;
427 }
428 
429 static void
daemon_unschedule_exit(GVfsDaemon * daemon)430 daemon_unschedule_exit (GVfsDaemon *daemon)
431 {
432   if (daemon->exit_tag != 0)
433     {
434       g_source_remove (daemon->exit_tag);
435       daemon->exit_tag = 0;
436     }
437 }
438 
439 static void
daemon_schedule_exit(GVfsDaemon * daemon)440 daemon_schedule_exit (GVfsDaemon *daemon)
441 {
442   if (daemon->exit_tag == 0)
443     daemon->exit_tag = g_timeout_add_seconds (1, (GSourceFunc)exit_at_idle, daemon);
444 }
445 
446 static void
job_source_new_job_callback(GVfsJobSource * job_source,GVfsJob * job,GVfsDaemon * daemon)447 job_source_new_job_callback (GVfsJobSource *job_source,
448 			     GVfsJob *job,
449 			     GVfsDaemon *daemon)
450 {
451   g_vfs_daemon_queue_job (daemon, job);
452 }
453 
454 static void
job_source_closed_callback(GVfsJobSource * job_source,GVfsDaemon * daemon)455 job_source_closed_callback (GVfsJobSource *job_source,
456 			    GVfsDaemon *daemon)
457 {
458   g_mutex_lock (&daemon->lock);
459 
460   daemon->job_sources = g_list_remove (daemon->job_sources,
461 				       job_source);
462 
463   g_signal_handlers_disconnect_by_func (job_source,
464 					(GCallback)job_source_new_job_callback,
465 					daemon);
466   g_signal_handlers_disconnect_by_func (job_source,
467 					(GCallback)job_source_closed_callback,
468 					daemon);
469 
470   g_object_unref (job_source);
471 
472   if (daemon->job_sources == NULL)
473     daemon_schedule_exit (daemon);
474 
475   g_mutex_unlock (&daemon->lock);
476 }
477 
478 static void
re_register_jobs_cb(GVfsBackend * backend,GAsyncResult * res,gpointer user_data)479 re_register_jobs_cb (GVfsBackend *backend,
480                      GAsyncResult *res,
481                      gpointer user_data)
482 {
483   GError *error = NULL;
484 
485   g_vfs_backend_register_mount_finish (backend, res, &error);
486   g_debug ("re_register_jobs_cb, error: %p\n", error);
487   g_clear_error (&error);
488 }
489 
490 static void
g_vfs_daemon_re_register_job_sources(GVfsDaemon * daemon)491 g_vfs_daemon_re_register_job_sources (GVfsDaemon *daemon)
492 {
493   GList *l;
494 
495   g_mutex_lock (&daemon->lock);
496 
497   for (l = daemon->job_sources; l != NULL; l = l->next)
498     {
499       if (G_VFS_IS_BACKEND (l->data))
500 	{
501 	  GVfsBackend *backend = G_VFS_BACKEND (l->data);
502 
503 	  /* Only re-register if we registered before, not e.g
504 	     if we're currently mounting. */
505 	  if (g_vfs_backend_is_mounted (backend))
506 	    g_vfs_backend_register_mount (backend, (GAsyncReadyCallback) re_register_jobs_cb, NULL);
507 	}
508     }
509 
510   g_mutex_unlock (&daemon->lock);
511 }
512 
513 void
g_vfs_daemon_add_job_source(GVfsDaemon * daemon,GVfsJobSource * job_source)514 g_vfs_daemon_add_job_source (GVfsDaemon *daemon,
515 			     GVfsJobSource *job_source)
516 {
517   g_debug ("Added new job source %p (%s)\n", job_source, g_type_name_from_instance ((gpointer)job_source));
518 
519   g_mutex_lock (&daemon->lock);
520 
521   daemon_unschedule_exit (daemon);
522 
523   g_object_ref (job_source);
524   daemon->job_sources = g_list_append (daemon->job_sources,
525 					     job_source);
526   g_signal_connect (job_source, "new_job",
527 		    (GCallback)job_source_new_job_callback, daemon);
528   g_signal_connect (job_source, "closed",
529 		    (GCallback)job_source_closed_callback, daemon);
530 
531   g_mutex_unlock (&daemon->lock);
532 }
533 
534 static void
unref_skeleton(gpointer object)535 unref_skeleton (gpointer object)
536 {
537   GDBusInterfaceSkeleton *skeleton = object;
538 
539   g_dbus_interface_skeleton_unexport (skeleton);
540   g_object_unref (skeleton);
541 }
542 
543 static void
peer_register_skeleton(const gchar * obj_path,RegisteredPath * reg_path,GDBusConnection * dbus_conn)544 peer_register_skeleton (const gchar *obj_path,
545                         RegisteredPath *reg_path,
546                         GDBusConnection *dbus_conn)
547 {
548   GDBusInterfaceSkeleton *skeleton;
549 
550   if (! g_hash_table_contains (reg_path->client_skeletons, dbus_conn))
551     {
552       skeleton = reg_path->callback (dbus_conn, obj_path, reg_path->data);
553       g_hash_table_insert (reg_path->client_skeletons, dbus_conn, skeleton);
554     }
555   else
556     {
557       /* Interface skeleton has been already registered on the connection, skipping */
558     }
559 }
560 
561 static void
client_conn_register_skeleton(GDBusConnection * dbus_conn,gpointer value,RegisteredPath * reg_path)562 client_conn_register_skeleton (GDBusConnection *dbus_conn,
563                                gpointer value,
564                                RegisteredPath *reg_path)
565 {
566   peer_register_skeleton (reg_path->obj_path, reg_path, dbus_conn);
567 }
568 
569 /* This registers a dbus interface skeleton on *all* connections, client and session bus */
570 /* The object path needs to be unique globally. */
571 void
g_vfs_daemon_register_path(GVfsDaemon * daemon,const char * obj_path,GVfsRegisterPathCallback callback,gpointer user_data)572 g_vfs_daemon_register_path (GVfsDaemon *daemon,
573                             const char *obj_path,
574                             GVfsRegisterPathCallback callback,
575                             gpointer user_data)
576 {
577   RegisteredPath *data;
578 
579   data = g_new0 (RegisteredPath, 1);
580   data->obj_path = g_strdup (obj_path);
581   data->callback = callback;
582   data->data = user_data;
583   data->client_skeletons = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)unref_skeleton);
584 
585   g_hash_table_insert (daemon->registered_paths, g_strdup (obj_path), data);
586 
587   /* Export the newly registered interface skeleton on session bus */
588   /* TODO: change the way we export skeletons on connections once
589    *       https://bugzilla.gnome.org/show_bug.cgi?id=662718 is in place.
590    */
591   data->session_skeleton = callback (daemon->conn, obj_path, user_data);
592 
593   /* Export this newly registered path to all active client connections */
594   g_hash_table_foreach (daemon->client_connections, (GHFunc) client_conn_register_skeleton, data);
595 }
596 
597 void
g_vfs_daemon_unregister_path(GVfsDaemon * daemon,const char * obj_path)598 g_vfs_daemon_unregister_path (GVfsDaemon *daemon,
599 			      const char *obj_path)
600 {
601   g_hash_table_remove (daemon->registered_paths, obj_path);
602 }
603 
604 /* NOTE: Might be emitted on a thread */
605 static void
job_new_source_callback(GVfsJob * job,GVfsJobSource * job_source,GVfsDaemon * daemon)606 job_new_source_callback (GVfsJob *job,
607 			 GVfsJobSource *job_source,
608 			 GVfsDaemon *daemon)
609 {
610   g_vfs_daemon_add_job_source (daemon, job_source);
611 }
612 
613 /* NOTE: Might be emitted on a thread */
614 static void
job_finished_callback(GVfsJob * job,GVfsDaemon * daemon)615 job_finished_callback (GVfsJob *job,
616 		       GVfsDaemon *daemon)
617 {
618 
619   g_signal_handlers_disconnect_by_func (job,
620 					(GCallback)job_new_source_callback,
621 					daemon);
622   g_signal_handlers_disconnect_by_func (job,
623 					(GCallback)job_finished_callback,
624 					daemon);
625 
626   g_mutex_lock (&daemon->lock);
627   daemon->jobs = g_list_remove (daemon->jobs, job);
628   g_mutex_unlock (&daemon->lock);
629 
630   g_object_unref (job);
631 }
632 
633 void
g_vfs_daemon_queue_job(GVfsDaemon * daemon,GVfsJob * job)634 g_vfs_daemon_queue_job (GVfsDaemon *daemon,
635 			GVfsJob *job)
636 {
637   g_debug ("Queued new job %p (%s)\n", job, g_type_name_from_instance ((gpointer)job));
638 
639   g_object_ref (job);
640   g_signal_connect (job, "finished", (GCallback)job_finished_callback, daemon);
641   g_signal_connect (job, "new_source", (GCallback)job_new_source_callback, daemon);
642 
643   g_mutex_lock (&daemon->lock);
644   daemon->jobs = g_list_prepend (daemon->jobs, job);
645   g_mutex_unlock (&daemon->lock);
646 
647   /* Can we start the job immediately / async */
648   if (!g_vfs_job_try (job))
649     {
650       /* Couldn't finish / run async, queue worker thread */
651       g_thread_pool_push (daemon->thread_pool, job, NULL); /* TODO: Check error */
652     }
653 }
654 
655 static void
new_connection_data_free(void * memory)656 new_connection_data_free (void *memory)
657 {
658   NewConnectionData *data = memory;
659   gchar *socket;
660 
661   /* Remove the socket and dir after connected */
662   if (data->socket_dir)
663     {
664       socket = g_strdup_printf ("%s/socket", data->socket_dir);
665       g_unlink (socket);
666       g_free (socket);
667       rmdir (data->socket_dir);
668       g_free (data->socket_dir);
669     }
670 
671   g_free (data);
672 }
673 
674 static void
peer_unregister_skeleton(const gchar * obj_path,RegisteredPath * reg_path,GDBusConnection * dbus_conn)675 peer_unregister_skeleton (const gchar *obj_path,
676                           RegisteredPath *reg_path,
677                           GDBusConnection *dbus_conn)
678 {
679   g_hash_table_remove (reg_path->client_skeletons, dbus_conn);
680 }
681 
682 static void
peer_connection_closed(GDBusConnection * connection,gboolean remote_peer_vanished,GError * error,gpointer user_data)683 peer_connection_closed (GDBusConnection *connection,
684                         gboolean         remote_peer_vanished,
685                         GError          *error,
686                         gpointer         user_data)
687 {
688   GVfsDaemon *daemon = G_VFS_DAEMON (user_data);
689   GList *l;
690   GVfsDBusDaemon *daemon_skeleton;
691   GVfsJob *job_to_cancel;
692 
693   do
694     {
695       job_to_cancel = NULL;
696 
697       g_mutex_lock (&daemon->lock);
698       for (l = daemon->jobs; l != NULL; l = l->next)
699         {
700           GVfsJob *job = G_VFS_JOB (l->data);
701 
702           if (G_VFS_IS_JOB_DBUS (job) &&
703               !g_vfs_job_is_cancelled (job) &&
704               G_VFS_JOB_DBUS (job)->invocation &&
705               g_dbus_method_invocation_get_connection (G_VFS_JOB_DBUS (job)->invocation) == connection)
706             {
707               job_to_cancel = g_object_ref (job);
708               break;
709             }
710         }
711       g_mutex_unlock (&daemon->lock);
712 
713       if (job_to_cancel)
714         {
715           g_vfs_job_cancel (job_to_cancel);
716           g_object_unref (job_to_cancel);
717         }
718     }
719   while (job_to_cancel != NULL);
720 
721   daemon_skeleton = g_object_get_data (G_OBJECT (connection), "daemon_skeleton");
722   /* daemon_skeleton should be always valid in this case */
723   g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (daemon_skeleton));
724 
725   g_hash_table_remove (daemon->client_connections, connection);
726 
727   /* Unexport the registered interface skeletons */
728   g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_unregister_skeleton, connection);
729 
730   /* The peer-to-peer connection was disconnected */
731   g_signal_handlers_disconnect_by_data (connection, user_data);
732   g_object_unref (connection);
733 }
734 
735 static void
daemon_peer_connection_setup(GVfsDaemon * daemon,GDBusConnection * dbus_conn,NewConnectionData * data)736 daemon_peer_connection_setup (GVfsDaemon *daemon,
737                               GDBusConnection *dbus_conn,
738 			      NewConnectionData *data)
739 {
740   GVfsDBusDaemon *daemon_skeleton;
741   GError *error;
742 
743   daemon_skeleton = gvfs_dbus_daemon_skeleton_new ();
744   g_signal_connect (daemon_skeleton, "handle-cancel", G_CALLBACK (handle_cancel), daemon);
745 
746   error = NULL;
747   if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (daemon_skeleton),
748                                          dbus_conn,
749                                          G_VFS_DBUS_DAEMON_PATH,
750                                          &error))
751     {
752       g_warning ("Failed to accept client: %s, %s (%s, %d)", "object registration failed",
753                  error->message, g_quark_to_string (error->domain), error->code);
754       g_error_free (error);
755       g_object_unref (data->conn);
756       goto error_out;
757     }
758   g_object_set_data_full (G_OBJECT (data->conn), "daemon_skeleton", daemon_skeleton, (GDestroyNotify) g_object_unref);
759 
760   /* Export registered interface skeletons on this new connection */
761   g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_register_skeleton, dbus_conn);
762 
763   g_hash_table_insert (daemon->client_connections, g_object_ref (dbus_conn), NULL);
764 
765   g_signal_connect (data->conn, "closed", G_CALLBACK (peer_connection_closed), data->daemon);
766 
767  error_out:
768   new_connection_data_free (data);
769 }
770 
771 #ifdef __linux__
772 #define USE_ABSTRACT_SOCKETS
773 #endif
774 
775 #ifndef USE_ABSTRACT_SOCKETS
776 static gboolean
test_safe_socket_dir(const char * dirname)777 test_safe_socket_dir (const char *dirname)
778 {
779   struct stat statbuf;
780 
781   if (g_stat (dirname, &statbuf) != 0)
782     return FALSE;
783 
784 #ifndef G_PLATFORM_WIN32
785   if (statbuf.st_uid != getuid ())
786     return FALSE;
787 
788   if ((statbuf.st_mode & (S_IRWXG|S_IRWXO)) ||
789       !S_ISDIR (statbuf.st_mode))
790     return FALSE;
791 #endif
792 
793   return TRUE;
794 }
795 
796 
797 static char *
create_socket_dir(void)798 create_socket_dir (void)
799 {
800   char *dirname;
801   long iteration = 0;
802   char *safe_dir;
803   gchar tmp[9];
804   int i;
805 
806   safe_dir = NULL;
807   do
808     {
809       g_free (safe_dir);
810 
811       gvfs_randomize_string (tmp, 8);
812       tmp[8] = '\0';
813 
814       dirname = g_strdup_printf ("gvfs-%s-%s",
815 				 g_get_user_name (), tmp);
816       safe_dir = g_build_filename (g_get_tmp_dir (), dirname, NULL);
817       g_free (dirname);
818 
819       if (g_mkdir (safe_dir, 0700) < 0)
820 	{
821 	  switch (errno)
822 	    {
823 	    case EACCES:
824 	      g_error ("I can't write to '%s', daemon init failed",
825 		       safe_dir);
826 	      break;
827 
828 	    case ENAMETOOLONG:
829 	      g_error ("Name '%s' too long your system is broken",
830 		       safe_dir);
831 	      break;
832 
833 	    case ENOMEM:
834 #ifdef ELOOP
835 	    case ELOOP:
836 #endif
837 	    case ENOSPC:
838 	    case ENOTDIR:
839 	    case ENOENT:
840 	      g_error ("Resource problem creating '%s'", safe_dir);
841 	      break;
842 
843 	    default: /* carry on going */
844 	      break;
845 	    }
846 	}
847       /* Possible race - so we re-scan. */
848 
849       if (iteration++ == 1000)
850 	g_error ("Cannot find a safe socket path in '%s'", g_get_tmp_dir ());
851     }
852   while (!test_safe_socket_dir (safe_dir));
853 
854   return safe_dir;
855 }
856 #endif
857 
858 static void
generate_address(char ** address,char ** folder)859 generate_address (char **address,
860 		  char **folder)
861 {
862   *address = NULL;
863   *folder = NULL;
864 
865 #ifdef USE_ABSTRACT_SOCKETS
866   {
867     gchar  tmp[9];
868 
869     gvfs_randomize_string (tmp, 8);
870     tmp[8] = '\0';
871     *address = g_strdup_printf ("unix:abstract=/dbus-vfs-daemon/socket-%s", tmp);
872   }
873 #else
874   {
875     char *dir;
876 
877     dir = create_socket_dir ();
878     *address = g_strdup_printf ("unix:path=%s/socket", dir);
879     *folder = dir;
880   }
881 #endif
882 }
883 
884 static gboolean
daemon_new_connection_func(GDBusServer * server,GDBusConnection * connection,gpointer user_data)885 daemon_new_connection_func (GDBusServer *server,
886                             GDBusConnection *connection,
887                             gpointer user_data)
888 {
889   NewConnectionData *data;
890 
891   data = user_data;
892 
893   /* Take ownership */
894   data->conn = g_object_ref (connection);
895 
896   daemon_peer_connection_setup (data->daemon, data->conn, data);
897 
898   /* Kill the server, no more need for it */
899   g_dbus_server_stop (server);
900   g_object_unref (server);
901 
902   return TRUE;
903 }
904 
905 static gboolean
handle_get_connection(GVfsDBusDaemon * object,GDBusMethodInvocation * invocation,gpointer user_data)906 handle_get_connection (GVfsDBusDaemon *object,
907                        GDBusMethodInvocation *invocation,
908                        gpointer user_data)
909 {
910   GVfsDaemon *daemon = G_VFS_DAEMON (user_data);
911   GDBusServer *server;
912   GError *error;
913   gchar *address1;
914   NewConnectionData *data;
915   char *socket_dir;
916   gchar *guid;
917 
918   generate_address (&address1, &socket_dir);
919 
920   data = g_new (NewConnectionData, 1);
921   data->daemon = daemon;
922   data->socket_dir = socket_dir;
923   data->conn = NULL;
924 
925   guid = g_dbus_generate_guid ();
926   error = NULL;
927   server = g_dbus_server_new_sync (address1,
928                                    G_DBUS_SERVER_FLAGS_NONE,
929                                    guid,
930                                    daemon->auth_observer,
931                                    NULL, /* GCancellable */
932                                    &error);
933   g_free (guid);
934 
935   if (server == NULL)
936     {
937       g_dbus_method_invocation_return_gerror (invocation, error);
938       g_printerr ("daemon: Error creating server at address %s: %s\n", address1, error->message);
939       g_error_free (error);
940       goto error_out;
941     }
942 
943   g_dbus_server_start (server);
944   data->server = server;
945 
946   g_signal_connect (server, "new-connection", G_CALLBACK (daemon_new_connection_func), data);
947 
948   gvfs_dbus_daemon_complete_get_connection (object,
949                                             invocation,
950                                             address1,
951                                             "");
952 
953   g_free (address1);
954   return TRUE;
955 
956  error_out:
957   new_connection_data_free (data);
958   g_free (address1);
959   return TRUE;
960 }
961 
962 static gboolean
handle_cancel(GVfsDBusDaemon * object,GDBusMethodInvocation * invocation,guint arg_serial,gpointer user_data)963 handle_cancel (GVfsDBusDaemon *object,
964                GDBusMethodInvocation *invocation,
965                guint arg_serial,
966                gpointer user_data)
967 {
968   GVfsDaemon *daemon = G_VFS_DAEMON (user_data);
969   GList *l;
970   GVfsJob *job_to_cancel = NULL;
971 
972   g_mutex_lock (&daemon->lock);
973   for (l = daemon->jobs; l != NULL; l = l->next)
974     {
975       GVfsJob *job = G_VFS_JOB (l->data);
976 
977       if (G_VFS_IS_JOB_DBUS (job) &&
978           g_vfs_job_dbus_is_serial (G_VFS_JOB_DBUS (job),
979                                     g_dbus_method_invocation_get_connection (invocation),
980                                     arg_serial))
981         {
982           job_to_cancel = g_object_ref (job);
983           break;
984         }
985     }
986   g_mutex_unlock (&daemon->lock);
987 
988   if (job_to_cancel)
989     {
990       g_vfs_job_cancel (job_to_cancel);
991       g_object_unref (job_to_cancel);
992     }
993 
994   gvfs_dbus_daemon_complete_cancel (object, invocation);
995 
996   return TRUE;
997 }
998 
999 static gboolean
handle_list_monitor_implementations(GVfsDBusDaemon * object,GDBusMethodInvocation * invocation,gpointer user_data)1000 handle_list_monitor_implementations (GVfsDBusDaemon        *object,
1001 				     GDBusMethodInvocation *invocation,
1002 				     gpointer               user_data)
1003 {
1004   GList *impls, *l;
1005   GVariantBuilder builder;
1006 
1007   impls = g_vfs_list_monitor_implementations ();
1008 
1009   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ssbia{sv})"));
1010 
1011   for (l = impls; l != NULL; l = l->next)
1012     {
1013       GVfsMonitorImplementation *impl = l->data;
1014 
1015       g_variant_builder_add_value (&builder, g_vfs_monitor_implementation_to_dbus (impl));
1016     }
1017 
1018   g_list_free_full (impls, (GDestroyNotify)g_vfs_monitor_implementation_free);
1019 
1020   gvfs_dbus_daemon_complete_list_monitor_implementations (object,
1021 							  invocation,
1022 							  g_variant_builder_end (&builder));
1023 
1024   return TRUE;
1025 }
1026 
1027 static gboolean
daemon_handle_mount(GVfsDBusMountable * object,GDBusMethodInvocation * invocation,GVariant * arg_mount_spec,gboolean arg_automount,GVariant * arg_mount_source,gpointer user_data)1028 daemon_handle_mount (GVfsDBusMountable *object,
1029                      GDBusMethodInvocation *invocation,
1030                      GVariant *arg_mount_spec,
1031                      gboolean arg_automount,
1032                      GVariant *arg_mount_source,
1033                      gpointer user_data)
1034 {
1035   GVfsDaemon *daemon = G_VFS_DAEMON (user_data);
1036   GMountSpec *mount_spec;
1037   GMountSource *mount_source;
1038 
1039   mount_spec = g_mount_spec_from_dbus (arg_mount_spec);
1040   if (mount_spec == NULL)
1041     g_dbus_method_invocation_return_error_literal (invocation,
1042                                                    G_IO_ERROR,
1043                                                    G_IO_ERROR_INVALID_ARGUMENT,
1044                                                    "Error in mount spec");
1045   else
1046     {
1047       mount_source = g_mount_source_from_dbus (arg_mount_source);
1048       g_vfs_daemon_initiate_mount (daemon, mount_spec, mount_source, arg_automount,
1049                                    object, invocation);
1050       g_object_unref (mount_source);
1051       g_mount_spec_unref (mount_spec);
1052     }
1053 
1054   return TRUE;
1055 }
1056 
1057 void
g_vfs_daemon_initiate_mount(GVfsDaemon * daemon,GMountSpec * mount_spec,GMountSource * mount_source,gboolean is_automount,GVfsDBusMountable * object,GDBusMethodInvocation * invocation)1058 g_vfs_daemon_initiate_mount (GVfsDaemon *daemon,
1059 			     GMountSpec *mount_spec,
1060 			     GMountSource *mount_source,
1061 			     gboolean is_automount,
1062 			     GVfsDBusMountable *object,
1063 			     GDBusMethodInvocation *invocation)
1064 {
1065   const char *type;
1066   GType backend_type;
1067   char *obj_path;
1068   GVfsJob *job;
1069   GVfsBackend *backend;
1070 
1071   type = g_mount_spec_get_type (mount_spec);
1072 
1073   backend_type = G_TYPE_INVALID;
1074   if (type)
1075     backend_type = g_vfs_lookup_backend (type);
1076 
1077   if (backend_type == G_TYPE_INVALID)
1078     {
1079       if (invocation)
1080         g_dbus_method_invocation_return_error_literal (invocation,
1081                                                        G_IO_ERROR,
1082                                                        G_IO_ERROR_FAILED,
1083                                                        "Invalid backend type");
1084       else
1085 	g_warning ("Error mounting: invalid backend type\n");
1086       return;
1087     }
1088 
1089   obj_path = g_strdup_printf ("/org/gtk/vfs/mount/%d", ++daemon->mount_counter);
1090   backend = g_object_new (backend_type,
1091 			  "daemon", daemon,
1092 			  "object-path", obj_path,
1093 			  NULL);
1094   g_free (obj_path);
1095 
1096   g_vfs_daemon_add_job_source (daemon, G_VFS_JOB_SOURCE (backend));
1097   g_object_unref (backend);
1098 
1099   job = g_vfs_job_mount_new (mount_spec, mount_source, is_automount, object, invocation, backend);
1100   g_vfs_daemon_queue_job (daemon, job);
1101   g_object_unref (job);
1102 }
1103 
1104 /**
1105  * g_vfs_daemon_get_blocking_processes:
1106  * @daemon: A #GVfsDaemon.
1107  *
1108  * Gets all processes that blocks unmounting, e.g. processes with open
1109  * file handles. Returned array could be empty in spite of
1110  * g_vfs_daemon_has_blocking_processes returns TRUE, because for jobs without
1111  * channel we can't get #GPid.
1112  *
1113  * Returns: An array of #GPid. Free with g_array_unref().
1114  */
1115 GArray *
g_vfs_daemon_get_blocking_processes(GVfsDaemon * daemon)1116 g_vfs_daemon_get_blocking_processes (GVfsDaemon *daemon)
1117 {
1118   GArray *processes;
1119   GList *l;
1120 
1121   g_mutex_lock (&daemon->lock);
1122 
1123   processes = g_array_new (FALSE, FALSE, sizeof (GPid));
1124   for (l = daemon->job_sources; l != NULL; l = l->next)
1125     {
1126       if (G_VFS_IS_CHANNEL (l->data))
1127         {
1128           GPid pid;
1129           pid = g_vfs_channel_get_actual_consumer (G_VFS_CHANNEL (l->data));
1130           g_array_append_val (processes, pid);
1131         }
1132     }
1133 
1134   g_mutex_unlock (&daemon->lock);
1135 
1136   return processes;
1137 }
1138 
1139 /**
1140  * g_vfs_daemon_has_blocking_processes:
1141  * @daemon: A #GVfsDaemon.
1142  *
1143  * Determines if there are any jobs blocking unmounting, all jobs excepting
1144  * unmount job.
1145  *
1146  * Returns: TRUE if there are any blocking processes, or FALSE otherwise.
1147  */
1148 gboolean
g_vfs_daemon_has_blocking_processes(GVfsDaemon * daemon)1149 g_vfs_daemon_has_blocking_processes (GVfsDaemon *daemon)
1150 {
1151   GList *l;
1152 
1153   g_mutex_lock (&daemon->lock);
1154   for (l = daemon->jobs; l != NULL; l = l->next)
1155     {
1156       if (!G_VFS_IS_JOB_UNMOUNT (l->data))
1157         {
1158           g_debug ("blocking job: %p\n", l->data);
1159           g_mutex_unlock (&daemon->lock);
1160           return TRUE;
1161         }
1162     }
1163   g_mutex_unlock (&daemon->lock);
1164 
1165   return FALSE;
1166 }
1167 
1168 void
g_vfs_daemon_run_job_in_thread(GVfsDaemon * daemon,GVfsJob * job)1169 g_vfs_daemon_run_job_in_thread (GVfsDaemon *daemon,
1170 				GVfsJob    *job)
1171 {
1172   g_thread_pool_push (daemon->thread_pool, job, NULL); /* TODO: Check error */
1173 }
1174 
1175 void
g_vfs_daemon_close_active_channels(GVfsDaemon * daemon,GVfsBackend * backend)1176 g_vfs_daemon_close_active_channels (GVfsDaemon *daemon,
1177 				    GVfsBackend *backend)
1178 {
1179   GList *l;
1180   GVfsChannel *channel_to_close;
1181 
1182   do
1183     {
1184       channel_to_close = NULL;
1185 
1186       g_mutex_lock (&daemon->lock);
1187       for (l = daemon->job_sources; l != NULL; l = l->next)
1188         {
1189           if (G_VFS_IS_CHANNEL (l->data) &&
1190               g_vfs_channel_get_backend (G_VFS_CHANNEL (l->data)) == backend)
1191             {
1192               channel_to_close = g_object_ref (G_VFS_CHANNEL (l->data));
1193               break;
1194             }
1195         }
1196       g_mutex_unlock (&daemon->lock);
1197 
1198       if (channel_to_close)
1199         {
1200           g_vfs_channel_force_close (channel_to_close);
1201           g_object_unref (channel_to_close);
1202         }
1203     }
1204   while (channel_to_close != NULL);
1205 }
1206