New upstream version
[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 /*30 days in ms*/
42 #define INFINITE_TIMEOUT 10*24*60*60*1000
43
44 #define MOONSHOT_DBUS_NAME "org.janet.Moonshot"
45 #define MOONSHOT_DBUS_PATH "/org/janet/moonshot"
46
47 /* This library is overly complicated currently due to the requirement
48  * that it work on Debian Squeeze - this has GLib 2.24 which requires us
49  * to use dbus-glib instead of GDBus. If/when this requirement is
50  * dropped the DBus version of the library can be greatly simplified.
51  */
52
53 /* Note that ideally this library would not depend on GLib. This would be
54  * possible using libdbus directly and running our own message loop while
55  * waiting for calls.
56  */
57
58 void moonshot_free (void *data)
59 {
60     g_free (data);
61 }
62
63 static DBusGProxy *dbus_connect (MoonshotError **error)
64 {
65     DBusConnection  *connection;
66     DBusError        dbus_error;
67     DBusGConnection *g_connection;
68     DBusGProxy      *g_proxy;
69     GError          *g_error;
70     dbus_bool_t      name_has_owner;
71
72     g_return_val_if_fail (*error == NULL, NULL);
73
74     dbus_error_init (&dbus_error);
75
76     /* Check for moonshot server and start the service if possible. We use
77      * libdbus here because dbus-glib doesn't handle autostarting the service.
78      * If/when we move to GDBus this code can become a one-liner.
79      */
80
81     connection = dbus_bus_get (DBUS_BUS_SESSION, &dbus_error);
82
83     if (dbus_error_is_set (&dbus_error)) {
84         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
85                                      "DBus error: %s",
86                                      dbus_error.message);
87         dbus_error_free (&dbus_error);
88         return NULL;
89     }
90
91     name_has_owner  = dbus_bus_name_has_owner (connection,
92                                                MOONSHOT_DBUS_NAME,
93                                                &dbus_error);
94
95     if (dbus_error_is_set (&dbus_error)) {
96         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
97                                      "DBus error: %s",
98                                      dbus_error.message);
99         dbus_error_free (&dbus_error);
100         return NULL;
101     }
102
103     if (! name_has_owner) {
104         dbus_bus_start_service_by_name (connection,
105                                         MOONSHOT_DBUS_NAME,
106                                         0,
107                                         NULL,
108                                         &dbus_error);
109
110         if (dbus_error_is_set (&dbus_error)) {
111             if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
112                 /* Missing .service file; the moonshot-ui install is broken */
113                 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
114                                              "The Moonshot service was not found. "
115                                              "Please make sure that moonshot-ui is "
116                                              "correctly installed.");
117             } else {
118                 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
119                                              "DBus error: %s",
120                                              dbus_error.message);
121             }
122             dbus_error_free (&dbus_error);
123             return NULL;
124         }
125     }
126
127     /* Now the service should be running */
128     g_error = NULL;
129
130     g_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &g_error);
131
132     if (g_error != NULL) {
133         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
134                                      "DBus error: %s",
135                                      g_error->message);
136         g_error_free (g_error);
137         return NULL;
138     }
139
140     g_proxy = dbus_g_proxy_new_for_name_owner (g_connection,
141                                                MOONSHOT_DBUS_NAME,
142                                                MOONSHOT_DBUS_PATH,
143                                                MOONSHOT_DBUS_NAME,
144                                                &g_error);
145
146     if (g_error != NULL) {
147         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
148                                      "DBus error: %s",
149                                      g_error->message);
150         g_error_free (g_error);
151         return NULL;
152     }
153
154     return g_proxy; 
155 }
156
157 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
158 {
159     static DBusGProxy    *dbus_proxy = NULL;
160     static GStaticMutex   init_lock = G_STATIC_MUTEX_INIT;
161
162     g_static_mutex_lock (&init_lock);
163
164     if (dbus_proxy == NULL) {
165         /* Make sure GObject is initialised, in case we are the only user
166          * of GObject in the process
167          */
168         g_type_init ();
169         dbus_proxy = dbus_connect (error);
170     }
171
172     if (dbus_proxy != NULL)
173         g_object_ref (dbus_proxy);
174
175     g_static_mutex_unlock (&init_lock);
176
177     return dbus_proxy;
178 }
179
180 int moonshot_get_identity (const char     *nai,
181                            const char     *password,
182                            const char     *service,
183                            char          **nai_out,
184                            char          **password_out,
185                            char          **server_certificate_hash_out,
186                            char          **ca_certificate_out,
187                            char          **subject_name_constraint_out,
188                            char          **subject_alt_name_constraint_out,
189                            MoonshotError **error)
190 {
191     GError     *g_error = NULL;
192     DBusGProxy *dbus_proxy;
193     int         success;
194
195     dbus_proxy = get_dbus_proxy (error);
196
197     if (*error != NULL)
198         return FALSE;
199
200     g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
201
202     dbus_g_proxy_call_with_timeout (dbus_proxy,
203                        "GetIdentity",
204                                     INFINITE_TIMEOUT,
205                                     &g_error,
206                        G_TYPE_STRING, nai,
207                        G_TYPE_STRING, password,
208                        G_TYPE_STRING, service,
209                        G_TYPE_INVALID,
210                        G_TYPE_STRING, nai_out,
211                        G_TYPE_STRING, password_out,
212                        G_TYPE_STRING, server_certificate_hash_out,
213                        G_TYPE_STRING, ca_certificate_out,
214                        G_TYPE_STRING, subject_name_constraint_out,
215                        G_TYPE_STRING, subject_alt_name_constraint_out,
216                        G_TYPE_BOOLEAN, &success,
217                        G_TYPE_INVALID);
218
219     g_object_unref (dbus_proxy);
220
221     if (g_error != NULL) {
222         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
223                                      g_error->message);
224         return FALSE;
225     }
226
227     if (success == FALSE) {
228         *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
229                                      "No identity was returned by the Moonshot "
230                                      "user interface.");
231         return FALSE;
232     }
233
234     return TRUE;
235 }
236
237 int moonshot_get_default_identity (char          **nai_out,
238                                    char          **password_out,
239                                    char          **server_certificate_hash_out,
240                                    char          **ca_certificate_out,
241                                    char          **subject_name_constraint_out,
242                                    char          **subject_alt_name_constraint_out,
243                                    MoonshotError **error)
244 {
245     GError     *g_error = NULL;
246     DBusGProxy *dbus_proxy;
247     int         success = FALSE;
248
249     dbus_proxy = get_dbus_proxy (error);
250
251     if (*error != NULL)
252         return FALSE;
253
254     g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
255
256     dbus_g_proxy_call_with_timeout (dbus_proxy,
257                        "GetDefaultIdentity",
258                                     INFINITE_TIMEOUT,
259                        &g_error,
260                        G_TYPE_INVALID,
261                        G_TYPE_STRING, nai_out,
262                        G_TYPE_STRING, password_out,
263                        G_TYPE_STRING, server_certificate_hash_out,
264                        G_TYPE_STRING, ca_certificate_out,
265                        G_TYPE_STRING, subject_name_constraint_out,
266                        G_TYPE_STRING, subject_alt_name_constraint_out,
267                        G_TYPE_BOOLEAN, &success,
268                        G_TYPE_INVALID);
269
270     g_object_unref (dbus_proxy);
271
272     if (g_error != NULL) {
273         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
274                                      g_error->message);
275         return FALSE;
276     }
277
278     if (success == FALSE) {
279         *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
280                                      "No identity was returned by the Moonshot "
281                                      "user interface.");
282         return FALSE;
283     }
284
285     return TRUE;
286 }
287
288 int moonshot_install_id_card (const char     *display_name,
289                               const char     *user_name,
290                               const char     *password,
291                               const char     *realm,
292                               char           *rules_patterns[],
293                               int             rules_patterns_length,
294                               char           *rules_always_confirm[],
295                               int             rules_always_confirm_length,
296                               char           *services[],
297                               int             services_length,
298                               const char     *ca_cert,
299                               const char     *subject,
300                               const char     *subject_alt,
301                               const char     *server_cert,
302                               MoonshotError **error)
303 {
304     GError      *g_error = NULL;
305     DBusGProxy  *dbus_proxy;
306     int          success = FALSE;
307     int          i;
308     const char **rules_patterns_strv,
309                **rules_always_confirm_strv,
310                **services_strv;
311
312     dbus_proxy = get_dbus_proxy (error);
313
314     if (*error != NULL)
315         return FALSE;
316
317     g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
318     g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length, FALSE);
319
320     /* Marshall array and struct parameters for DBus */
321     rules_patterns_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
322     rules_always_confirm_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
323     services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
324
325     for (i = 0; i < rules_patterns_length; i ++) {
326         rules_patterns_strv[i] = rules_patterns[i];
327         rules_always_confirm_strv[i] = rules_always_confirm[i];
328     }
329
330     for (i = 0; i < services_length; i ++)
331         services_strv[i] = services[i];
332
333     rules_patterns_strv[rules_patterns_length] = NULL;
334     rules_always_confirm_strv[rules_patterns_length] = NULL;
335     services_strv[services_length] = NULL;
336
337     dbus_g_proxy_call (dbus_proxy,
338                        "InstallIdCard",
339                        &g_error,
340                        G_TYPE_STRING, display_name,
341                        G_TYPE_STRING, user_name,
342                        G_TYPE_STRING, password,
343                        G_TYPE_STRING, realm,
344                        G_TYPE_STRV, rules_patterns_strv,
345                        G_TYPE_STRV, rules_always_confirm_strv,
346                        G_TYPE_STRV, services_strv,
347                        G_TYPE_STRING, ca_cert,
348                        G_TYPE_STRING, subject,
349                        G_TYPE_STRING, subject_alt,
350                        G_TYPE_STRING, server_cert,
351                        G_TYPE_INVALID,
352                        G_TYPE_BOOLEAN, &success,
353                        G_TYPE_INVALID);
354
355     g_object_unref (dbus_proxy);
356
357     if (g_error != NULL) {
358         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
359                                      g_error->message);
360         return FALSE;
361     }
362
363     return success;
364 }