Implement web provisioning on Windows
[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 FALSE;
196
197     g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
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_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
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 }
282
283 int moonshot_install_id_card (const char     *display_name,
284                               const char     *user_name,
285                               const char     *password,
286                               const char     *realm,
287                               char           *rules_patterns[],
288                               int             rules_patterns_length,
289                               char           *rules_always_confirm[],
290                               int             rules_always_confirm_length,
291                               char           *services[],
292                               int             services_length,
293                               const char     *ca_cert,
294                               const char     *subject,
295                               const char     *subject_alt,
296                               const char     *server_cert,
297                               MoonshotError **error)
298 {
299     GError      *g_error = NULL;
300     DBusGProxy  *dbus_proxy;
301     int          success = FALSE;
302     int          i;
303     const char **rules_patterns_strv,
304                **rules_always_confirm_strv,
305                **services_strv;
306
307     dbus_proxy = get_dbus_proxy (error);
308
309     if (*error != NULL)
310         return FALSE;
311
312     g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
313     g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length), FALSE);
314
315     /* Marshall array and struct parameters for DBus */
316     rules_patterns_strv = g_malloc ((rules_length + 1) * sizeof (const char *));
317     rules_always_confirm_strv = g_malloc ((rules_length + 1) * sizeof (const char *));
318     services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
319
320     for (i = 0; i < rules_patterns_length; i ++) {
321         rules_pattern_strv[i] = rules_patterns[i];
322         rules_always_confirm_strv[i] = rules_always_confirm[i];
323     }
324
325     for (i = 0; i < services_length; i ++)
326         services_strv[i] = services[i];
327
328     rules_pattern_strv[rules_patterns_length] = NULL;
329     rules_always_confirm_strv[rules_patterns_length] = NULL;
330     services_strv[services_length] = NULL;
331
332     dbus_g_proxy_call (dbus_proxy,
333                        "InstallIdCard",
334                        &g_error,
335                        G_TYPE_STRING, display_name,
336                        G_TYPE_STRING, user_name,
337                        G_TYPE_STRING, password,
338                        G_TYPE_STRING, realm,
339                        G_TYPE_STRV, rules_pattern_strv,
340                        G_TYPE_STRV, rules_always_confirm_strv,
341                        G_TYPE_STRV, services_strv,
342                        G_TYPE_STRING, ca_cert,
343                        G_TYPE_STRING, subject,
344                        G_TYPE_STRING, subject_alt,
345                        G_TYPE_STRING, server_cert,
346                        G_TYPE_INVALID,
347                        G_TYPE_BOOLEAN, &success,
348                        G_TYPE_INVALID);
349
350     g_object_unref (dbus_proxy);
351
352     if (g_error != NULL) {
353         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
354                                      g_error->message);
355         return FALSE;
356     }
357
358     return success;
359 }