1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	/* NetworkManager -- Network link manager
3    	 *
4    	 * This program is free software; you can redistribute it and/or modify
5    	 * it under the terms of the GNU General Public License as published by
6    	 * the Free Software Foundation; either version 2 of the License, or
7    	 * (at your option) any later version.
8    	 *
9    	 * This program is distributed in the hope that it will be useful,
10   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   	 * GNU General Public License for more details.
13   	 *
14   	 * You should have received a copy of the GNU General Public License along
15   	 * with this program; if not, write to the Free Software Foundation, Inc.,
16   	 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17   	 *
18   	 * Copyright (C) 2006 - 2013 Red Hat, Inc.
19   	 * Copyright (C) 2006 - 2008 Novell, Inc.
20   	 */
21   	
22   	#include "config.h"
23   	#include <unistd.h>
24   	#include <sys/stat.h>
25   	#include <sys/types.h>
26   	
27   	#include "NetworkManager.h"
28   	#include "nm-dbus-manager.h"
29   	#include "nm-glib-compat.h"
30   	#include "nm-properties-changed-signal.h"
31   	
32   	#include <dbus/dbus.h>
33   	#include <dbus/dbus-glib.h>
34   	#include <dbus/dbus-glib-lowlevel.h>
35   	#include <string.h>
36   	#include "nm-logging.h"
37   	
38   	#define PRIV_SOCK_PATH NMRUNDIR "/private"
39   	#define PRIV_SOCK_TAG  "private"
40   	
41   	enum {
42   		DBUS_CONNECTION_CHANGED = 0,
43   		NAME_OWNER_CHANGED,
44   		PRIVATE_CONNECTION_NEW,
45   		PRIVATE_CONNECTION_DISCONNECTED,
46   		NUMBER_OF_SIGNALS
47   	};
48   	
49   	static guint signals[NUMBER_OF_SIGNALS];
50   	
51   	G_DEFINE_TYPE(NMDBusManager, nm_dbus_manager, G_TYPE_OBJECT)
52   	
53   	#define NM_DBUS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
54   	                                        NM_TYPE_DBUS_MANAGER, \
55   	                                        NMDBusManagerPrivate))
56   	
57   	typedef struct _PrivateServer PrivateServer;
58   	
59   	typedef struct {
60   		DBusConnection *connection;
61   		DBusGConnection *g_connection;
62   		GHashTable *exported;
63   		gboolean started;
64   	
65   		GSList *private_servers;
66   		PrivateServer *priv_server;
67   	
68   		DBusGProxy *proxy;
69   		guint proxy_destroy_id;
70   	
71   		guint reconnect_id;
72   	} NMDBusManagerPrivate;
73   	
74   	static gboolean nm_dbus_manager_init_bus (NMDBusManager *self);
75   	static void nm_dbus_manager_cleanup (NMDBusManager *self, gboolean dispose);
76   	static void start_reconnection_timeout (NMDBusManager *self);
77   	static void object_destroyed (NMDBusManager *self, gpointer object);
78   	
79   	NMDBusManager *
80   	nm_dbus_manager_get (void)
81   	{
82   		static NMDBusManager *singleton = NULL;
83   		static gsize once = 0;
84   	
85   		if (g_once_init_enter (&once)) {
86   			singleton = (NMDBusManager *) g_object_new (NM_TYPE_DBUS_MANAGER, NULL);
87   			g_assert (singleton);
88   			if (!nm_dbus_manager_init_bus (singleton))
89   				start_reconnection_timeout (singleton);
90   			g_once_init_leave (&once, 1);
91   		}
92   		return singleton;
93   	}
94   	
95   	/**************************************************************/
96   	
97   	struct _PrivateServer {
98   		char *tag;
99   		GQuark detail;
100  		char *address;
101  		DBusServer *server;
102  		GHashTable *connections;
103  		NMDBusManager *manager;
104  	};
105  	
106  	static DBusHandlerResult
107  	private_server_message_filter (DBusConnection *conn,
108  	                               DBusMessage *message,
109  	                               void *data)
110  	{
111  		PrivateServer *s = data;
112  	
113  		/* Clean up after the connection */
114  		if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
115  			nm_log_dbg (LOGD_CORE, "(%s) closed connection %p on private socket.",
116  			            s->tag, conn);
117  	
118  			/* Emit this for the manager */
119  			g_signal_emit (s->manager,
120  			               signals[PRIVATE_CONNECTION_DISCONNECTED],
121  			               s->detail,
122  			               dbus_connection_get_g_connection (conn));
123  	
124  			g_hash_table_remove (s->connections, conn);
125  	
126  			/* Let dbus-glib process the message too */
127  			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
128  		}
129  	
130  		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
131  	}
132  	
133  	static dbus_bool_t
134  	allow_only_root (DBusConnection *connection, unsigned long uid, void *data)
135  	{
136  		return uid == 0;
137  	}
138  	
139  	static void
140  	private_server_new_connection (DBusServer *server,
141  	                               DBusConnection *conn,
142  	                               gpointer user_data)
143  	{
144  		PrivateServer *s = user_data;
145  		static guint32 counter = 0;
146  		char *sender;
147  	
148  		if (!dbus_connection_add_filter (conn, private_server_message_filter, s, NULL)) {
149  			dbus_connection_close (conn);
150  			return;
151  		}
152  		dbus_connection_set_unix_user_function (conn, allow_only_root, NULL, NULL);
153  		dbus_connection_setup_with_g_main (conn, NULL);
154  	
155  		/* Fake a sender since private connections don't have one */
156  		sender = g_strdup_printf ("x:y:%d", counter++);
157  		g_hash_table_insert (s->connections, dbus_connection_ref (conn), sender);
158  	
159  		nm_log_dbg (LOGD_CORE, "(%s) accepted connection %p on private socket.", s->tag, conn);
160  	
161  		/* Emit this for the manager */
162  		g_signal_emit (s->manager,
163  		               signals[PRIVATE_CONNECTION_NEW],
164  		               s->detail,
165  		               dbus_connection_get_g_connection (conn));
166  	}
167  	
168  	static void
169  	private_server_dbus_connection_destroy (DBusConnection *conn)
170  	{
171  		if (dbus_connection_get_is_connected (conn))
172  			dbus_connection_close (conn);
173  		dbus_connection_unref (conn);
174  	}
175  	
176  	static PrivateServer *
177  	private_server_new (const char *path,
178  	                    const char *tag,
179  	                    NMDBusManager *manager)
180  	{
181  		PrivateServer *s;
182  		DBusServer *server;
183  		DBusError error;
184  		char *address;
185  	
186  		unlink (path);
187  		address = g_strdup_printf ("unix:path=%s", path);
188  	
189  		nm_log_dbg (LOGD_CORE, "(%s) creating private socket %s.", tag, address);
190  	
191  		dbus_error_init (&error);
192  		server = dbus_server_listen (address, &error);
193  		if (!server) {
194  			nm_log_warn (LOGD_CORE, "(%s) failed to set up private socket %s: %s",
195  			             tag, address, error.message);
196  			dbus_error_free (&error);
197  			return NULL;
198  		}
199  	
200  		s = g_malloc0 (sizeof (*s));
201  		s->address = address;
202  		s->server = server;
203  		dbus_server_setup_with_g_main (s->server, NULL);
204  		dbus_server_set_new_connection_function (s->server, private_server_new_connection, s, NULL);
205  	
206  		s->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
207  		                                        (GDestroyNotify) private_server_dbus_connection_destroy,
208  		                                        g_free);
209  		s->manager = manager;
210  		s->tag = g_strdup (tag);
211  		s->detail = g_quark_from_string (s->tag);
212  	
213  		return s;
214  	}
215  	
216  	static void
217  	private_server_free (gpointer ptr)
218  	{
219  		PrivateServer *s = ptr;
220  	
221  		unlink (s->address);
222  		g_free (s->address);
223  		g_free (s->tag);
224  		g_hash_table_destroy (s->connections);
225  		dbus_server_unref (s->server);
226  		memset (s, 0, sizeof (*s));
227  		g_free (s);
228  	}
229  	
230  	void
231  	nm_dbus_manager_private_server_register (NMDBusManager *self,
232  	                                         const char *path,
233  	                                         const char *tag)
234  	{
235  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
236  		PrivateServer *s;
237  		GSList *iter;
238  	
239  	#if !HAVE_DBUS_GLIB_100
240  		g_assert_not_reached ();
241  	#endif
242  	
243  		g_return_if_fail (self != NULL);
244  		g_return_if_fail (path != NULL);
245  		g_return_if_fail (tag != NULL);
246  	
247  		/* Only one instance per tag; but don't warn */
248  		for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
249  			s = iter->data;
250  			if (g_strcmp0 (tag, s->tag) == 0)
251  				return;
252  		}
253  	
254  		s = private_server_new (path, tag, self);
255  		if (s)
256  			priv->private_servers = g_slist_append (priv->private_servers, s);
257  	}
258  	
259  	static const char *
260  	private_server_get_connection_owner (PrivateServer *s, DBusGConnection *connection)
261  	{
262  		g_return_val_if_fail (s != NULL, NULL);
263  		g_return_val_if_fail (connection != NULL, NULL);
264  	
265  		return g_hash_table_lookup (s->connections, dbus_g_connection_get_connection (connection));
266  	}
267  	
268  	/**************************************************************/
269  	
270  	/**
271  	 * _get_caller_info_from_context():
272  	 *
273  	 * Given a dbus-glib method invocation, or a DBusConnection + DBusMessage,
274  	 * return the sender and the UID of the sender.
275  	 */
276  	static gboolean
277  	_get_caller_info (NMDBusManager *self,
278  	                  DBusGMethodInvocation *context,
279  	                  DBusConnection *connection,
280  	                  DBusMessage *message,
281  	                  char **out_sender,
282  	                  gulong *out_uid)
283  	{
284  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
285  		DBusGConnection *gconn;
286  		char *sender;
287  		const char *priv_sender;
288  		DBusError error;
289  		GSList *iter;
290  	
291  		if (context) {
292  			gconn = dbus_g_method_invocation_get_g_connection (context);
293  			g_assert (gconn);
294  			connection = dbus_g_connection_get_connection (gconn);
295  	
296  			/* only bus connections will have a sender */
297  			sender = dbus_g_method_get_sender (context);
298  		} else {
299  			g_assert (message);
300  			sender = g_strdup (dbus_message_get_sender (message));
301  		}
302  		g_assert (connection);
303  	
304  		if (!sender) {
305  			/* Might be a private connection, for which we fake a sender */
306  			for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
307  				PrivateServer *s = iter->data;
308  	
309  				priv_sender = g_hash_table_lookup (s->connections, connection);
310  				if (priv_sender) {
311  					if (out_uid)
312  						*out_uid = 0;
313  					if (out_sender)
314  						*out_sender = g_strdup (priv_sender);
315  					return TRUE;
316  				}
317  			}
318  			return FALSE;
319  		}
320  	
321  		/* Bus connections always have a sender */
322  		g_assert (sender);
323  		if (out_uid) {
324  			dbus_error_init (&error);
325  			*out_uid = dbus_bus_get_unix_user (connection, sender, &error);
326  			if (dbus_error_is_set (&error)) {
327  				dbus_error_free (&error);
328  				*out_uid = G_MAXULONG;
329  				g_free (sender);
330  				return FALSE;
331  			}
332  		}
333  	
334  		if (out_sender)
335  			*out_sender = g_strdup (sender);
336  	
337  		g_free (sender);
338  		return TRUE;
339  	}
340  	
341  	gboolean
342  	nm_dbus_manager_get_caller_info (NMDBusManager *self,
343  	                                 DBusGMethodInvocation *context,
344  	                                 char **out_sender,
345  	                                 gulong *out_uid)
346  	{
347  		return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid);
348  	}
349  	
350  	gboolean
351  	nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self,
352  	                                              DBusConnection *connection,
353  	                                              DBusMessage *message,
354  	                                              char **out_sender,
355  	                                              gulong *out_uid)
356  	{
357  		return _get_caller_info (self, NULL, connection, message, out_sender, out_uid);
358  	}
359  	
360  	gboolean
361  	nm_dbus_manager_get_unix_user (NMDBusManager *self,
362  	                               const char *sender,
363  	                               gulong *out_uid)
364  	{
365  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
366  		GSList *iter;
367  		DBusError error;
368  	
369  		g_return_val_if_fail (sender != NULL, FALSE);
370  		g_return_val_if_fail (out_uid != NULL, FALSE);
371  	
372  		/* Check if it's a private connection sender, which we fake */
373  		for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
374  			PrivateServer *s = iter->data;
375  			GHashTableIter hiter;
376  			const char *priv_sender;
377  	
378  			g_hash_table_iter_init (&hiter, s->connections);
379  			while (g_hash_table_iter_next (&hiter, NULL, (gpointer) &priv_sender)) {
380  				if (g_strcmp0 (sender, priv_sender) == 0) {
381  					*out_uid = 0;
382  					return TRUE;
383  				}
384  			}
385  		}
386  	
387  		/* Otherwise, a bus connection */
388  		dbus_error_init (&error);
389  		*out_uid = dbus_bus_get_unix_user (priv->connection, sender, &error);
390  		if (dbus_error_is_set (&error)) {
391  			nm_log_warn (LOGD_CORE, "Failed to get unix user for dbus sender '%s': %s",
392  			             sender, error.message);
393  			return FALSE;
394  		}
395  	
396  		return TRUE;
397  	}
398  	
399  	/**************************************************************/
400  	
401  	#if HAVE_DBUS_GLIB_100
402  	static void
403  	private_connection_new (NMDBusManager *self, DBusGConnection *connection)
404  	{
405  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
406  		GHashTableIter iter;
407  		GObject *object;
408  		const char *path;
409  	
410  		/* Register all exported objects on this private connection */
411  		g_hash_table_iter_init (&iter, priv->exported);
412  		while (g_hash_table_iter_next (&iter, (gpointer) &object, (gpointer) &path)) {
413  			dbus_g_connection_register_g_object (connection, path, object);
414  			nm_log_dbg (LOGD_CORE, "(%s) registered %p (%s) at '%s' on private socket.",
415  			            PRIV_SOCK_TAG, object, G_OBJECT_TYPE_NAME (object), path);
416  		}
417  	}
418  	
419  	static void
420  	private_connection_disconnected (NMDBusManager *self, DBusGConnection *connection)
421  	{
422  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
423  		const char *owner;
424  	
425  		owner = private_server_get_connection_owner (priv->priv_server, connection);
426  		g_assert (owner);
427  	
428  		/* Fake a NameOwnerChanged to let listerners know this owner has quit */
429  		g_signal_emit (G_OBJECT (self), signals[NAME_OWNER_CHANGED],
430  		               0, owner, owner, NULL);
431  	}
432  	#endif  /* HAVE_DBUS_GLIB_100 */
433  	
434  	static void
435  	nm_dbus_manager_init (NMDBusManager *self)
436  	{
437  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
438  	
439  		priv->exported = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
440  	
441  	#if HAVE_DBUS_GLIB_100
442  		/* Set up our main private DBus socket */
(1) Event check_return: Calling function "mkdir("/var/run/NetworkManager", 448U)" without checking return value. This library function may fail and return an error code.
(2) Event unchecked_value: No check of the return value of "mkdir("/var/run/NetworkManager", 448U)".
443  		mkdir (NMRUNDIR, 0700);
444  		priv->priv_server = private_server_new (PRIV_SOCK_PATH, PRIV_SOCK_TAG, self);
445  		if (priv->priv_server) {
446  			priv->private_servers = g_slist_append (priv->private_servers, priv->priv_server);
447  	
448  			g_signal_connect (self,
449  			                  NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG,
450  			                  (GCallback) private_connection_new,
451  			                  NULL);
452  			g_signal_connect (self,
453  			                  NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG,
454  			                  (GCallback) private_connection_disconnected,
455  			                  NULL);
456  		}
457  	#endif
458  	}
459  	
460  	static void
461  	nm_dbus_manager_dispose (GObject *object)
462  	{
463  		NMDBusManager *self = NM_DBUS_MANAGER (object);
464  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
465  		GHashTableIter iter;
466  		GObject *exported;
467  	
468  		if (priv->exported) {
469  			g_hash_table_iter_init (&iter, priv->exported);
470  			while (g_hash_table_iter_next (&iter, (gpointer) &exported, NULL))
471  				g_object_weak_unref (exported, (GWeakNotify) object_destroyed, self);
472  	
473  			g_hash_table_destroy (priv->exported);
474  			priv->exported = NULL;
475  		}
476  	
477  		g_slist_free_full (priv->private_servers, private_server_free);
478  		priv->private_servers = NULL;
479  		priv->priv_server = NULL;
480  	
481  		nm_dbus_manager_cleanup (self, TRUE);
482  	
483  		if (priv->reconnect_id) {
484  			g_source_remove (priv->reconnect_id);
485  			priv->reconnect_id = 0;
486  		}
487  	
488  		G_OBJECT_CLASS (nm_dbus_manager_parent_class)->dispose (object);
489  	}
490  	
491  	static void
492  	nm_dbus_manager_class_init (NMDBusManagerClass *klass)
493  	{
494  		GObjectClass *object_class = G_OBJECT_CLASS (klass);
495  	
496  		g_type_class_add_private (klass, sizeof (NMDBusManagerPrivate));
497  	
498  		object_class->dispose = nm_dbus_manager_dispose;
499  	
500  		signals[DBUS_CONNECTION_CHANGED] =
501  			g_signal_new (NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED,
502  			              G_OBJECT_CLASS_TYPE (object_class),
503  			              G_SIGNAL_RUN_LAST,
504  			              G_STRUCT_OFFSET (NMDBusManagerClass, dbus_connection_changed),
505  			              NULL, NULL, NULL,
506  			              G_TYPE_NONE, 1, G_TYPE_POINTER);
507  	
508  		signals[NAME_OWNER_CHANGED] =
509  			g_signal_new (NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
510  			              G_OBJECT_CLASS_TYPE (object_class),
511  			              G_SIGNAL_RUN_LAST,
512  			              G_STRUCT_OFFSET (NMDBusManagerClass, name_owner_changed),
513  			              NULL, NULL, NULL,
514  			              G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
515  	
516  		signals[PRIVATE_CONNECTION_NEW] =
517  			g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW,
518  			              G_OBJECT_CLASS_TYPE (object_class),
519  			              G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
520  			              G_STRUCT_OFFSET (NMDBusManagerClass, private_connection_new),
521  			              NULL, NULL, NULL,
522  			              G_TYPE_NONE, 1, G_TYPE_POINTER);
523  	
524  		signals[PRIVATE_CONNECTION_DISCONNECTED] =
525  			g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED,
526  			              G_OBJECT_CLASS_TYPE (object_class),
527  			              G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
528  			              G_STRUCT_OFFSET (NMDBusManagerClass, private_connection_disconnected),
529  			              NULL, NULL, NULL,
530  			              G_TYPE_NONE, 1, G_TYPE_POINTER);
531  	}
532  	
533  	
534  	/* Only cleanup a specific dbus connection, not all our private data */
535  	static void
536  	nm_dbus_manager_cleanup (NMDBusManager *self, gboolean dispose)
537  	{
538  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
539  	
540  		if (priv->proxy) {
541  			if (dispose) {
542  				g_signal_handler_disconnect (priv->proxy, priv->proxy_destroy_id);
543  				priv->proxy_destroy_id = 0;
544  			}
545  			g_object_unref (priv->proxy);
546  			priv->proxy = NULL;
547  		}
548  	
549  		if (priv->g_connection) {
550  			dbus_g_connection_unref (priv->g_connection);
551  			priv->g_connection = NULL;
552  			priv->connection = NULL;
553  		}
554  	
555  		priv->started = FALSE;
556  	}
557  	
558  	static gboolean
559  	nm_dbus_manager_reconnect (gpointer user_data)
560  	{
561  		NMDBusManager *self = NM_DBUS_MANAGER (user_data);
562  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
563  	
564  		g_assert (self != NULL);
565  	
566  		if (nm_dbus_manager_init_bus (self)) {
567  			if (nm_dbus_manager_start_service (self)) {
568  				nm_log_info (LOGD_CORE, "reconnected to the system bus.");
569  				g_signal_emit (self, signals[DBUS_CONNECTION_CHANGED],
570  				               0, priv->connection);
571  				priv->reconnect_id = 0;
572  				return FALSE;
573  			}
574  		}
575  	
576  		/* Try again */
577  		nm_dbus_manager_cleanup (self, FALSE);
578  		return TRUE;
579  	}
580  	
581  	static void
582  	start_reconnection_timeout (NMDBusManager *self)
583  	{
584  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
585  	
586  		if (priv->reconnect_id)
587  			g_source_remove (priv->reconnect_id);
588  	
589  		/* Schedule timeout for reconnection attempts */
590  		priv->reconnect_id = g_timeout_add_seconds (3, nm_dbus_manager_reconnect, self);
591  	}
592  	
593  	char *
594  	nm_dbus_manager_get_name_owner (NMDBusManager *self,
595  	                                const char *name,
596  	                                GError **error)
597  	{
598  		char *owner = NULL;
599  	
600  		g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL);
601  		g_return_val_if_fail (name != NULL, NULL);
602  		if (error)
603  			g_return_val_if_fail (*error == NULL, NULL);
604  	
605  		if (!NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy)
606  			return NULL;
607  	
608  		if (!dbus_g_proxy_call_with_timeout (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy,
609  		                                     "GetNameOwner", 2000, error,
610  		                                     G_TYPE_STRING, name,
611  		                                     G_TYPE_INVALID,
612  		                                     G_TYPE_STRING, &owner,
613  		                                     G_TYPE_INVALID)) {
614  			return NULL;
615  		}
616  	
617  		return owner;
618  	}
619  	
620  	gboolean
621  	nm_dbus_manager_name_has_owner (NMDBusManager *self,
622  	                                const char *name)
623  	{
624  		gboolean has_owner = FALSE;
625  		GError *err = NULL;
626  	
627  		g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE);
628  		g_return_val_if_fail (name != NULL, FALSE);
629  	
630  		if (!NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy)
631  			return FALSE;
632  	
633  		if (!dbus_g_proxy_call (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy,
634  						    "NameHasOwner", &err,
635  						    G_TYPE_STRING, name,
636  						    G_TYPE_INVALID,
637  						    G_TYPE_BOOLEAN, &has_owner,
638  						    G_TYPE_INVALID)) {
639  			nm_log_warn (LOGD_CORE, "NameHasOwner request failed: %s",
640  			             (err && err->message) ? err->message : "(unknown)");
641  			g_clear_error (&err);
642  		}
643  	
644  		return has_owner;
645  	}
646  	
647  	static void
648  	proxy_name_owner_changed (DBusGProxy *proxy,
649  						 const char *name,
650  						 const char *old_owner,
651  						 const char *new_owner,
652  						 gpointer user_data)
653  	{
654  		g_signal_emit (G_OBJECT (user_data), signals[NAME_OWNER_CHANGED],
655  		               0, name, old_owner, new_owner);
656  	}
657  	
658  	static void
659  	destroy_cb (DBusGProxy *proxy, gpointer user_data)
660  	{
661  		NMDBusManager *self = NM_DBUS_MANAGER (user_data);
662  	
663  		/* Clean up existing connection */
664  		nm_log_warn (LOGD_CORE, "disconnected by the system bus.");
665  		NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy = NULL;
666  	
667  		nm_dbus_manager_cleanup (self, FALSE);
668  	
669  		g_signal_emit (G_OBJECT (self), signals[DBUS_CONNECTION_CHANGED], 0, NULL);
670  	
671  		start_reconnection_timeout (self);
672  	}
673  	
674  	static gboolean
675  	nm_dbus_manager_init_bus (NMDBusManager *self)
676  	{
677  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
678  	
679  		if (priv->connection) {
680  			nm_log_warn (LOGD_CORE, "DBus Manager already has a valid connection.");
681  			return FALSE;
682  		}
683  	
684  		dbus_connection_set_change_sigpipe (TRUE);
685  	
686  		priv->g_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
687  		if (!priv->g_connection) {
688  			/* Log with 'info' severity; there won't be a bus daemon in minimal
689  			 * environments (eg, initrd) where we only want to use the private
690  			 * socket.
691  			 */
692  			nm_log_info (LOGD_CORE, "Could not connect to the system bus; only the "
693  			             "private D-Bus socket will be available.");
694  			return FALSE;
695  		}
696  	
697  		priv->connection = dbus_g_connection_get_connection (priv->g_connection);
698  		dbus_connection_set_exit_on_disconnect (priv->connection, FALSE);
699  	
700  		priv->proxy = dbus_g_proxy_new_for_name (priv->g_connection,
701  		                                         "org.freedesktop.DBus",
702  		                                         "/org/freedesktop/DBus",
703  		                                         "org.freedesktop.DBus");
704  	
705  		priv->proxy_destroy_id = g_signal_connect (priv->proxy, "destroy",
706  		                                           G_CALLBACK (destroy_cb), self);
707  	
708  		dbus_g_proxy_add_signal (priv->proxy, "NameOwnerChanged",
709  		                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
710  		                         G_TYPE_INVALID);
711  		dbus_g_proxy_connect_signal (priv->proxy,
712  		                             "NameOwnerChanged",
713  		                             G_CALLBACK (proxy_name_owner_changed),
714  		                             self, NULL);
715  		return TRUE;
716  	}
717  	
718  	/* Register our service on the bus; shouldn't be called until
719  	 * all necessary message handlers have been registered, because
720  	 * when we register on the bus, clients may start to call.
721  	 */
722  	gboolean
723  	nm_dbus_manager_start_service (NMDBusManager *self)
724  	{
725  		NMDBusManagerPrivate *priv;
726  		int result;
727  		GError *err = NULL;
728  	
729  		g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE);
730  	
731  		priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
732  	
733  		if (priv->started) {
734  			nm_log_err (LOGD_CORE, "Service has already started.");
735  			return FALSE;
736  		}
737  	
738  		/* Pointless to request a name when we aren't connected to the bus */
739  		if (!priv->proxy)
740  			return FALSE;
741  	
742  		if (!dbus_g_proxy_call (priv->proxy, "RequestName", &err,
743  		                        G_TYPE_STRING, NM_DBUS_SERVICE,
744  		                        G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
745  		                        G_TYPE_INVALID,
746  		                        G_TYPE_UINT, &result,
747  		                        G_TYPE_INVALID)) {
748  			nm_log_err (LOGD_CORE, "Could not acquire the NetworkManager service.\n"
749  			            "  Error: '%s'",
750  			            (err && err->message) ? err->message : "(unknown)");
751  			g_error_free (err);
752  			return FALSE;
753  		}
754  	
755  		if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
756  			nm_log_err (LOGD_CORE, "Could not acquire the NetworkManager service as it is already taken.");
757  			return FALSE;
758  		}
759  	
760  		priv->started = TRUE;
761  		return priv->started;
762  	}
763  	
764  	DBusConnection *
765  	nm_dbus_manager_get_dbus_connection (NMDBusManager *self)
766  	{
767  		g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL);
768  	
769  		return NM_DBUS_MANAGER_GET_PRIVATE (self)->connection;
770  	}
771  	
772  	DBusGConnection *
773  	nm_dbus_manager_get_connection (NMDBusManager *self)
774  	{
775  		g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL);
776  	
777  		return NM_DBUS_MANAGER_GET_PRIVATE (self)->g_connection;
778  	}
779  	
780  	static void
781  	object_destroyed (NMDBusManager *self, gpointer object)
782  	{
783  		g_hash_table_remove (NM_DBUS_MANAGER_GET_PRIVATE (self)->exported, object);
784  	}
785  	
786  	void
787  	nm_dbus_manager_register_exported_type (NMDBusManager         *self,
788  	                                        GType                  object_type,
789  	                                        const DBusGObjectInfo *info)
790  	{
791  		const char *properties_info, *dbus_name, *gobject_name, *tmp_access;
792  	
793  		dbus_g_object_type_install_info (object_type, info);
794  		if (!info->exported_properties)
795  			return;
796  	
797  		properties_info = info->exported_properties;
798  		while (*properties_info) {
799  			/* The format is: "interface\0DBusPropertyName\0gobject_property_name\0access\0" */
800  			dbus_name = strchr (properties_info, '\0') + 1;
801  			gobject_name = strchr (dbus_name, '\0') + 1;
802  			tmp_access = strchr (gobject_name, '\0') + 1;
803  			properties_info = strchr (tmp_access, '\0') + 1;
804  	
805  			/* Note that nm-properties-changed-signal takes advantage of the
806  			 * fact that @dbus_name and @gobject_name are static data that won't
807  			 * ever be freed.
808  			 */
809  			nm_properties_changed_signal_add_property (object_type, dbus_name, gobject_name);
810  		}
811  	}
812  	
813  	void
814  	nm_dbus_manager_register_object (NMDBusManager *self,
815  	                                 const char *path,
816  	                                 gpointer object)
817  	{
818  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
819  		GHashTableIter iter;
820  		DBusConnection *connection;
821  	
822  		g_assert (G_IS_OBJECT (object));
823  	
824  		g_warn_if_fail (g_hash_table_lookup (priv->exported, object) == NULL);
825  		g_hash_table_insert (priv->exported, G_OBJECT (object), g_strdup (path));
826  	
827  		if (priv->g_connection)
828  			dbus_g_connection_register_g_object (priv->g_connection, path, G_OBJECT (object));
829  	
830  		if (priv->priv_server) {
831  			g_hash_table_iter_init (&iter, priv->priv_server->connections);
832  			while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) {
833  				dbus_g_connection_register_g_object (dbus_connection_get_g_connection (connection),
834  				                                     path,
835  				                                     G_OBJECT (object));
836  			}
837  		}
838  	
839  		g_object_weak_ref (G_OBJECT (object), (GWeakNotify) object_destroyed, self);
840  	}
841  	
842  	void
843  	nm_dbus_manager_unregister_object (NMDBusManager *self, gpointer object)
844  	{
845  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
846  		GHashTableIter iter;
847  		DBusConnection *connection;
848  	
849  		g_assert (G_IS_OBJECT (object));
850  	
851  		g_hash_table_remove (NM_DBUS_MANAGER_GET_PRIVATE (self)->exported, G_OBJECT (object));
852  		g_object_weak_unref (G_OBJECT (object), (GWeakNotify) object_destroyed, self);
853  	
854  		if (priv->g_connection)
855  			dbus_g_connection_unregister_g_object (priv->g_connection, G_OBJECT (object));
856  	
857  		if (priv->priv_server) {
858  			g_hash_table_iter_init (&iter, priv->priv_server->connections);
859  			while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) {
860  				dbus_g_connection_unregister_g_object (dbus_connection_get_g_connection (connection),
861  				                                       G_OBJECT (object));
862  			}
863  		}
864  	}
865  	
866  	/**
867  	 * nm_dbus_manager_new_proxy:
868  	 * @self: the #NMDBusManager
869  	 * @context: the method call context this proxy should be created
870  	 * @name: any name on the message bus
871  	 * @path: name of the object instance to call methods on
872  	 * @iface: name of the interface to call methods on
873  	 *
874  	 * Creates a new proxy for a name on a given bus.  Since the process which
875  	 * called the D-Bus method could be coming from a private connection or the
876  	 * system bus connection, differnet proxies must be created for each case.  This
877  	 * function abstracts that.
878  	 *
879  	 * Returns: a #DBusGProxy capable of calling D-Bus methods of the calling process
880  	 */
881  	DBusGProxy *
882  	nm_dbus_manager_new_proxy (NMDBusManager *self,
883  	                           DBusGMethodInvocation *context,
884  	                           const char *name,
885  	                           const char *path,
886  	                           const char *iface)
887  	{
888  		NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
889  		DBusGConnection *connection;
890  		GSList *iter;
891  		const char *owner;
892  	
893  		connection = dbus_g_method_invocation_get_g_connection (context);
894  		g_assert (connection);
895  	
896  		/* Might be a private connection, for which we fake a sender */
897  		for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
898  			PrivateServer *s = iter->data;
899  	
900  			owner = private_server_get_connection_owner (s, connection);
901  			if (owner) {
902  				g_assert_cmpstr (owner, ==, name);
903  				return dbus_g_proxy_new_for_peer (connection, path, iface);
904  			}
905  		}
906  	
907  		return dbus_g_proxy_new_for_name (connection, name, path, iface);
908  	}
909  	
910  	#if !HAVE_DBUS_GLIB_GMI_GET_CONNECTION
911  	struct _HACKDBusGMethodInvocation {
912  	  DBusGConnection *connection;
913  	  /* ... */
914  	};
915  	
916  	DBusGConnection *
917  	dbus_g_method_invocation_get_g_connection (DBusGMethodInvocation *context)
918  	{
919  		/* Evil hack; this method exists in dbus-glib >= 101, but if we don't
920  		 * have that, emulate it.
921  		 */
922  		return ((struct _HACKDBusGMethodInvocation *) context)->connection;
923  	}
924  	#endif  /* HAVE_DBUS_GLIB_GMI_GET_CONNECTION */
925