1 /* libmoonshot - Moonshot client library
2 * Copyright (c) 2011, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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
32 * Author: Sam Thursfield <samthursfield@codethink.co.uk>
38 #include <dbus/dbus-glib.h>
39 #include <dbus/dbus.h>
40 #include <dbus/dbus-glib-lowlevel.h>
41 #include <glib/gspawn.h>
44 #include "libmoonshot.h"
45 #include "libmoonshot-common.h"
48 #define INFINITE_TIMEOUT 10*24*60*60*1000
50 #define MOONSHOT_DBUS_NAME "org.janet.Moonshot"
51 #define MOONSHOT_DBUS_PATH "/org/janet/moonshot"
53 /* This library is overly complicated currently due to the requirement
54 * that it work on Debian Squeeze - this has GLib 2.24 which requires us
55 * to use dbus-glib instead of GDBus. If/when this requirement is
56 * dropped the DBus version of the library can be greatly simplified.
59 /* Note that ideally this library would not depend on GLib. This would be
60 * possible using libdbus directly and running our own message loop while
64 void moonshot_free (void *data)
68 static char *moonshot_launch_argv[] = {
69 MOONSHOT_LAUNCH_SCRIPT, NULL
72 static DBusGConnection *dbus_launch_moonshot()
74 DBusGConnection *connection = NULL;
78 gint fd_stdin = -1, fd_stdout = -1;
80 dbus_error_init(&dbus_error);
81 char dbus_address[1024];
83 if (g_spawn_async_with_pipes( NULL /*cwd*/,
84 moonshot_launch_argv, NULL /*environ*/,
85 0 /*flags*/, NULL /*setup*/, NULL,
86 &child_pid, &fd_stdin, &fd_stdout,
87 NULL /*stderr*/, NULL /*error*/) == 0 ) {
91 addresslen = read( fd_stdout, dbus_address, sizeof dbus_address);
93 /* we require at least 2 octets of address because we trim the newline*/
94 if (addresslen <= 1) {
95 fail: dbus_error_free(&dbus_error);
96 if (connection != NULL)
97 dbus_g_connection_unref(connection);
99 g_spawn_close_pid(child_pid);
102 dbus_address[addresslen-1] = '\0';
103 connection = dbus_g_connection_open(dbus_address, &error);
108 if (!dbus_bus_register(dbus_g_connection_get_connection(connection),
115 static DBusGProxy *dbus_connect (MoonshotError **error)
117 DBusConnection *dbconnection;
118 DBusError dbus_error;
119 DBusGConnection *connection;
121 GError *g_error = NULL;
122 dbus_bool_t name_has_owner;
124 g_return_val_if_fail (*error == NULL, NULL);
126 dbus_error_init (&dbus_error);
128 /* Check for moonshot server and start the service if possible. We use
129 * libdbus here because dbus-glib doesn't handle autostarting the service.
130 * If/when we move to GDBus this code can become a one-liner.
133 connection = dbus_g_bus_get (DBUS_BUS_SESSION, &g_error);
135 if (g_error_matches(g_error, DBUS_GERROR, DBUS_GERROR_NOT_SUPPORTED)) {
136 /*Generally this means autolaunch failed because probably DISPLAY is unset*/
137 connection = dbus_launch_moonshot();
138 if (connection != NULL) {
139 g_error_free(g_error);
144 if (g_error != NULL) {
145 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
148 g_error_free (g_error);
152 dbconnection = dbus_g_connection_get_connection(connection);
153 name_has_owner = dbus_bus_name_has_owner (dbconnection,
157 if (dbus_error_is_set (&dbus_error)) {
158 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
161 dbus_error_free (&dbus_error);
165 if (! name_has_owner) {
166 dbus_bus_start_service_by_name (dbconnection,
172 if (dbus_error_is_set (&dbus_error)) {
173 if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
174 /* Missing .service file; the moonshot-ui install is broken */
175 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
176 "The Moonshot service was not found. "
177 "Please make sure that moonshot-ui is "
178 "correctly installed.");
180 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
184 dbus_error_free (&dbus_error);
189 /* Now the service should be running */
192 g_proxy = dbus_g_proxy_new_for_name_owner (connection,
198 if (g_error != NULL) {
199 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
202 g_error_free (g_error);
209 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
211 static DBusGProxy *dbus_proxy = NULL;
212 static GStaticMutex init_lock = G_STATIC_MUTEX_INIT;
214 g_static_mutex_lock (&init_lock);
216 if (dbus_proxy == NULL) {
217 /* Make sure GObject is initialised, in case we are the only user
218 * of GObject in the process
221 dbus_proxy = dbus_connect (error);
224 if (dbus_proxy != NULL)
225 g_object_ref (dbus_proxy);
227 g_static_mutex_unlock (&init_lock);
232 int moonshot_get_identity (const char *nai,
233 const char *password,
237 char **server_certificate_hash_out,
238 char **ca_certificate_out,
239 char **subject_name_constraint_out,
240 char **subject_alt_name_constraint_out,
241 MoonshotError **error)
243 GError *g_error = NULL;
244 DBusGProxy *dbus_proxy;
247 dbus_proxy = get_dbus_proxy (error);
252 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
254 dbus_g_proxy_call_with_timeout (dbus_proxy,
259 G_TYPE_STRING, password,
260 G_TYPE_STRING, service,
262 G_TYPE_STRING, nai_out,
263 G_TYPE_STRING, password_out,
264 G_TYPE_STRING, server_certificate_hash_out,
265 G_TYPE_STRING, ca_certificate_out,
266 G_TYPE_STRING, subject_name_constraint_out,
267 G_TYPE_STRING, subject_alt_name_constraint_out,
268 G_TYPE_BOOLEAN, &success,
271 g_object_unref (dbus_proxy);
273 if (g_error != NULL) {
274 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
279 if (success == FALSE) {
280 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
281 "No identity was returned by the Moonshot "
289 int moonshot_get_default_identity (char **nai_out,
291 char **server_certificate_hash_out,
292 char **ca_certificate_out,
293 char **subject_name_constraint_out,
294 char **subject_alt_name_constraint_out,
295 MoonshotError **error)
297 GError *g_error = NULL;
298 DBusGProxy *dbus_proxy;
301 dbus_proxy = get_dbus_proxy (error);
306 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
308 dbus_g_proxy_call_with_timeout (dbus_proxy,
309 "GetDefaultIdentity",
313 G_TYPE_STRING, nai_out,
314 G_TYPE_STRING, password_out,
315 G_TYPE_STRING, server_certificate_hash_out,
316 G_TYPE_STRING, ca_certificate_out,
317 G_TYPE_STRING, subject_name_constraint_out,
318 G_TYPE_STRING, subject_alt_name_constraint_out,
319 G_TYPE_BOOLEAN, &success,
322 g_object_unref (dbus_proxy);
324 if (g_error != NULL) {
325 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
330 if (success == FALSE) {
331 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
332 "No identity was returned by the Moonshot "
340 int moonshot_install_id_card (const char *display_name,
341 const char *user_name,
342 const char *password,
344 char *rules_patterns[],
345 int rules_patterns_length,
346 char *rules_always_confirm[],
347 int rules_always_confirm_length,
352 const char *subject_alt,
353 const char *server_cert,
354 int force_flat_file_store,
355 MoonshotError **error)
357 GError *g_error = NULL;
358 DBusGProxy *dbus_proxy;
361 const char **rules_patterns_strv,
362 **rules_always_confirm_strv,
365 dbus_proxy = get_dbus_proxy (error);
370 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
371 g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length, FALSE);
373 /* Marshall array and struct parameters for DBus */
374 rules_patterns_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
375 rules_always_confirm_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
376 services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
378 for (i = 0; i < rules_patterns_length; i ++) {
379 rules_patterns_strv[i] = rules_patterns[i];
380 rules_always_confirm_strv[i] = rules_always_confirm[i];
383 for (i = 0; i < services_length; i ++)
384 services_strv[i] = services[i];
386 rules_patterns_strv[rules_patterns_length] = NULL;
387 rules_always_confirm_strv[rules_patterns_length] = NULL;
388 services_strv[services_length] = NULL;
390 dbus_g_proxy_call (dbus_proxy,
393 G_TYPE_STRING, display_name,
394 G_TYPE_STRING, user_name,
395 G_TYPE_STRING, password,
396 G_TYPE_STRING, realm,
397 G_TYPE_STRV, rules_patterns_strv,
398 G_TYPE_STRV, rules_always_confirm_strv,
399 G_TYPE_STRV, services_strv,
400 G_TYPE_STRING, ca_cert,
401 G_TYPE_STRING, subject,
402 G_TYPE_STRING, subject_alt,
403 G_TYPE_STRING, server_cert,
404 G_TYPE_INT, force_flat_file_store,
406 G_TYPE_BOOLEAN, &success,
409 g_object_unref (dbus_proxy);
411 if (g_error != NULL) {
412 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,