Merge branch 'master' of ssh://69.25.196.28:822/srv/git/moonshot-ui
[moonshot-ui.git] / libmoonshot / libmoonshot-dbus.c
1 /* libmoonshot - Moonshot client library
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * Author: Sam Thursfield <samthursfield@codethink.co.uk>
33  */
34
35 #include <dbus/dbus-glib.h>
36 #include <dbus/dbus.h>
37
38 #include "libmoonshot.h"
39 #include "libmoonshot-common.h"
40
41 #define MOONSHOT_DBUS_NAME "org.janet.Moonshot"
42 #define MOONSHOT_DBUS_PATH "/org/janet/moonshot"
43
44 /* This library is overly complicated currently due to the requirement
45  * that it work on Debian Squeeze - this has GLib 2.24 which requires us
46  * to use dbus-glib instead of GDBus. If/when this requirement is
47  * dropped the DBus version of the library can be greatly simplified.
48  */
49
50 /* Note that ideally this library would not depend on GLib. This would be
51  * possible using libdbus directly and running our own message loop while
52  * waiting for calls.
53  */
54
55 void moonshot_free (void *data)
56 {
57     g_free (data);
58 }
59
60 static DBusGProxy *dbus_connect (MoonshotError **error)
61 {
62     DBusConnection  *connection;
63     DBusError        dbus_error;
64     DBusGConnection *g_connection;
65     DBusGProxy      *g_proxy;
66     GError          *g_error;
67     dbus_bool_t      name_has_owner;
68
69     g_return_val_if_fail (*error == NULL, NULL);
70
71     dbus_error_init (&dbus_error);
72
73     /* Check for moonshot server and start the service if possible. We use
74      * libdbus here because dbus-glib doesn't handle autostarting the service.
75      * If/when we move to GDBus this code can become a one-liner.
76      */
77
78     connection = dbus_bus_get (DBUS_BUS_SESSION, &dbus_error);
79
80     if (dbus_error_is_set (&dbus_error)) {
81         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
82                                      "DBus error: %s",
83                                      dbus_error.message);
84         dbus_error_free (&dbus_error);
85         return NULL;
86     }
87
88     name_has_owner  = dbus_bus_name_has_owner (connection,
89                                                MOONSHOT_DBUS_NAME,
90                                                &dbus_error);
91
92     if (dbus_error_is_set (&dbus_error)) {
93         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
94                                      "DBus error: %s",
95                                      dbus_error.message);
96         dbus_error_free (&dbus_error);
97         return NULL;
98     }
99
100     if (! name_has_owner) {
101         dbus_bus_start_service_by_name (connection,
102                                         MOONSHOT_DBUS_NAME,
103                                         0,
104                                         NULL,
105                                         &dbus_error);
106
107         if (dbus_error_is_set (&dbus_error)) {
108             if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
109                 /* Missing .service file; the moonshot-ui install is broken */
110                 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
111                                              "The Moonshot service was not found. "
112                                              "Please make sure that moonshot-ui is "
113                                              "correctly installed.");
114             } else {
115                 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
116                                              "DBus error: %s",
117                                              dbus_error.message);
118             }
119             dbus_error_free (&dbus_error);
120             return NULL;
121         }
122     }
123
124     /* Now the service should be running */
125     g_error = NULL;
126
127     g_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &g_error);
128
129     if (g_error != NULL) {
130         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
131                                      "DBus error: %s",
132                                      g_error->message);
133         g_error_free (g_error);
134         return NULL;
135     }
136
137     g_proxy = dbus_g_proxy_new_for_name_owner (g_connection,
138                                                MOONSHOT_DBUS_NAME,
139                                                MOONSHOT_DBUS_PATH,
140                                                MOONSHOT_DBUS_NAME,
141                                                &g_error);
142
143     if (g_error != NULL) {
144         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
145                                      "DBus error: %s",
146                                      g_error->message);
147         g_error_free (g_error);
148         return NULL;
149     }
150
151     return g_proxy; 
152 }
153
154 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
155 {
156     static DBusGProxy    *dbus_proxy = NULL;
157     static GStaticMutex   init_lock = G_STATIC_MUTEX_INIT;
158
159     g_static_mutex_lock (&init_lock);
160
161     if (dbus_proxy == NULL) {
162         /* Make sure GObject is initialised, in case we are the only user
163          * of GObject in the process
164          */
165         g_type_init ();
166         dbus_proxy = dbus_connect (error);
167     }
168
169     if (dbus_proxy != NULL)
170         g_object_ref (dbus_proxy);
171
172     g_static_mutex_unlock (&init_lock);
173
174     return dbus_proxy;
175 }
176
177 int moonshot_get_identity (const char     *nai,
178                            const char     *password,
179                            const char     *service,
180                            char          **nai_out,
181                            char          **password_out,
182                            char          **server_certificate_hash_out,
183                            char          **ca_certificate_out,
184                            char          **subject_name_constraint_out,
185                            char          **subject_alt_name_constraint_out,
186                            MoonshotError **error)
187 {
188     GError     *g_error = NULL;
189     DBusGProxy *dbus_proxy;
190     int         success;
191
192     dbus_proxy = get_dbus_proxy (error);
193
194     if (*error != NULL)
195         return;
196
197     g_return_if_fail (DBUS_IS_G_PROXY (dbus_proxy));
198
199     dbus_g_proxy_call (dbus_proxy,
200                        "GetIdentity",
201                        &g_error,
202                        G_TYPE_STRING, nai,
203                        G_TYPE_STRING, password,
204                        G_TYPE_STRING, service,
205                        G_TYPE_INVALID,
206                        G_TYPE_STRING, nai_out,
207                        G_TYPE_STRING, password_out,
208                        G_TYPE_STRING, server_certificate_hash_out,
209                        G_TYPE_STRING, ca_certificate_out,
210                        G_TYPE_STRING, subject_name_constraint_out,
211                        G_TYPE_STRING, subject_alt_name_constraint_out,
212                        G_TYPE_BOOLEAN, &success,
213                        G_TYPE_INVALID);
214
215     g_object_unref (dbus_proxy);
216
217     if (g_error != NULL) {
218         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
219                                      g_error->message);
220         return FALSE;
221     }
222
223     if (success == FALSE) {
224         *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
225                                      "No identity was returned by the Moonshot "
226                                      "user interface.");
227         return FALSE;
228     }
229
230     return TRUE;
231 }
232
233 int moonshot_get_default_identity (char          **nai_out,
234                                    char          **password_out,
235                                    char          **server_certificate_hash_out,
236                                    char          **ca_certificate_out,
237                                    char          **subject_name_constraint_out,
238                                    char          **subject_alt_name_constraint_out,
239                                    MoonshotError **error)
240 {
241     GError     *g_error = NULL;
242     DBusGProxy *dbus_proxy;
243     int         success = FALSE;
244
245     dbus_proxy = get_dbus_proxy (error);
246
247     if (*error != NULL)
248         return FALSE;
249
250     g_return_if_fail (DBUS_IS_G_PROXY (dbus_proxy));
251
252     dbus_g_proxy_call (dbus_proxy,
253                        "GetDefaultIdentity",
254                        &g_error,
255                        G_TYPE_INVALID,
256                        G_TYPE_STRING, nai_out,
257                        G_TYPE_STRING, password_out,
258                        G_TYPE_STRING, server_certificate_hash_out,
259                        G_TYPE_STRING, ca_certificate_out,
260                        G_TYPE_STRING, subject_name_constraint_out,
261                        G_TYPE_STRING, subject_alt_name_constraint_out,
262                        G_TYPE_BOOLEAN, &success,
263                        G_TYPE_INVALID);
264
265     g_object_unref (dbus_proxy);
266
267     if (g_error != NULL) {
268         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
269                                      g_error->message);
270         return FALSE;
271     }
272
273     if (success == FALSE) {
274         *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
275                                      "No identity was returned by the Moonshot "
276                                      "user interface.");
277         return FALSE;
278     }
279
280     return TRUE;
281 }