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 DBusConnection *dbus_launch_moonshot()
74 DBusConnection *connection = NULL;
77 gint fd_stdin = -1, fd_stdout = -1;
79 char dbus_address[1024];
81 if (g_spawn_async_with_pipes( NULL /*cwd*/,
82 moonshot_launch_argv, NULL /*environ*/,
83 0 /*flags*/, NULL /*setup*/, NULL,
84 &child_pid, &fd_stdin, &fd_stdout,
85 NULL /*stderr*/, NULL /*error*/) == 0 ) {
89 dbus_error_init(&dbus_error);
90 addresslen = read( fd_stdout, dbus_address, sizeof dbus_address);
92 /* we require at least 2 octets of address because we trim the newline*/
93 if (addresslen <= 1) {
94 fail: dbus_error_free(&dbus_error);
95 if (connection != NULL)
96 dbus_connection_unref(connection);
98 g_spawn_close_pid(child_pid);
101 dbus_address[addresslen-1] = '\0';
102 connection = dbus_connection_open(dbus_address, &dbus_error);
103 if (dbus_error_is_set(&dbus_error)) {
106 if (!dbus_bus_register(connection, &dbus_error))
112 static DBusGProxy *dbus_connect (MoonshotError **error)
114 DBusConnection *connection;
115 DBusError dbus_error;
116 DBusGConnection *g_connection;
118 GError *g_error = NULL;
119 dbus_bool_t name_has_owner;
121 g_return_val_if_fail (*error == NULL, NULL);
123 dbus_error_init (&dbus_error);
125 /* Check for moonshot server and start the service if possible. We use
126 * libdbus here because dbus-glib doesn't handle autostarting the service.
127 * If/when we move to GDBus this code can become a one-liner.
130 connection = dbus_bus_get (DBUS_BUS_SESSION, &dbus_error);
132 if (dbus_error_has_name(&dbus_error, DBUS_ERROR_NOT_SUPPORTED)) {
133 /*Generally this means autolaunch failed because probably DISPLAY is unset*/
134 connection = dbus_launch_moonshot();
135 if (connection != NULL) {
136 dbus_error_free(&dbus_error);
137 dbus_error_init(&dbus_error);
141 if (dbus_error_is_set (&dbus_error)) {
142 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
145 dbus_error_free (&dbus_error);
149 name_has_owner = dbus_bus_name_has_owner (connection,
153 if (dbus_error_is_set (&dbus_error)) {
154 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
157 dbus_error_free (&dbus_error);
161 if (! name_has_owner) {
162 dbus_bus_start_service_by_name (connection,
168 if (dbus_error_is_set (&dbus_error)) {
169 if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
170 /* Missing .service file; the moonshot-ui install is broken */
171 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
172 "The Moonshot service was not found. "
173 "Please make sure that moonshot-ui is "
174 "correctly installed.");
176 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
180 dbus_error_free (&dbus_error);
185 /* Now the service should be running */
188 g_connection = dbus_connection_get_g_connection(connection);
189 assert (g_connection != NULL);
190 g_proxy = dbus_g_proxy_new_for_name_owner (g_connection,
196 if (g_error != NULL) {
197 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
200 g_error_free (g_error);
207 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
209 static DBusGProxy *dbus_proxy = NULL;
210 static GStaticMutex init_lock = G_STATIC_MUTEX_INIT;
212 g_static_mutex_lock (&init_lock);
214 if (dbus_proxy == NULL) {
215 /* Make sure GObject is initialised, in case we are the only user
216 * of GObject in the process
219 dbus_proxy = dbus_connect (error);
222 if (dbus_proxy != NULL)
223 g_object_ref (dbus_proxy);
225 g_static_mutex_unlock (&init_lock);
230 int moonshot_get_identity (const char *nai,
231 const char *password,
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)
241 GError *g_error = NULL;
242 DBusGProxy *dbus_proxy;
245 dbus_proxy = get_dbus_proxy (error);
250 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
252 dbus_g_proxy_call_with_timeout (dbus_proxy,
257 G_TYPE_STRING, password,
258 G_TYPE_STRING, service,
260 G_TYPE_STRING, nai_out,
261 G_TYPE_STRING, password_out,
262 G_TYPE_STRING, server_certificate_hash_out,
263 G_TYPE_STRING, ca_certificate_out,
264 G_TYPE_STRING, subject_name_constraint_out,
265 G_TYPE_STRING, subject_alt_name_constraint_out,
266 G_TYPE_BOOLEAN, &success,
269 g_object_unref (dbus_proxy);
271 if (g_error != NULL) {
272 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
277 if (success == FALSE) {
278 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
279 "No identity was returned by the Moonshot "
287 int moonshot_get_default_identity (char **nai_out,
289 char **server_certificate_hash_out,
290 char **ca_certificate_out,
291 char **subject_name_constraint_out,
292 char **subject_alt_name_constraint_out,
293 MoonshotError **error)
295 GError *g_error = NULL;
296 DBusGProxy *dbus_proxy;
299 dbus_proxy = get_dbus_proxy (error);
304 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
306 dbus_g_proxy_call_with_timeout (dbus_proxy,
307 "GetDefaultIdentity",
311 G_TYPE_STRING, nai_out,
312 G_TYPE_STRING, password_out,
313 G_TYPE_STRING, server_certificate_hash_out,
314 G_TYPE_STRING, ca_certificate_out,
315 G_TYPE_STRING, subject_name_constraint_out,
316 G_TYPE_STRING, subject_alt_name_constraint_out,
317 G_TYPE_BOOLEAN, &success,
320 g_object_unref (dbus_proxy);
322 if (g_error != NULL) {
323 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
328 if (success == FALSE) {
329 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
330 "No identity was returned by the Moonshot "
338 int moonshot_install_id_card (const char *display_name,
339 const char *user_name,
340 const char *password,
342 char *rules_patterns[],
343 int rules_patterns_length,
344 char *rules_always_confirm[],
345 int rules_always_confirm_length,
350 const char *subject_alt,
351 const char *server_cert,
352 MoonshotError **error)
354 GError *g_error = NULL;
355 DBusGProxy *dbus_proxy;
358 const char **rules_patterns_strv,
359 **rules_always_confirm_strv,
362 dbus_proxy = get_dbus_proxy (error);
367 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
368 g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length, FALSE);
370 /* Marshall array and struct parameters for DBus */
371 rules_patterns_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
372 rules_always_confirm_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
373 services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
375 for (i = 0; i < rules_patterns_length; i ++) {
376 rules_patterns_strv[i] = rules_patterns[i];
377 rules_always_confirm_strv[i] = rules_always_confirm[i];
380 for (i = 0; i < services_length; i ++)
381 services_strv[i] = services[i];
383 rules_patterns_strv[rules_patterns_length] = NULL;
384 rules_always_confirm_strv[rules_patterns_length] = NULL;
385 services_strv[services_length] = NULL;
387 dbus_g_proxy_call (dbus_proxy,
390 G_TYPE_STRING, display_name,
391 G_TYPE_STRING, user_name,
392 G_TYPE_STRING, password,
393 G_TYPE_STRING, realm,
394 G_TYPE_STRV, rules_patterns_strv,
395 G_TYPE_STRV, rules_always_confirm_strv,
396 G_TYPE_STRV, services_strv,
397 G_TYPE_STRING, ca_cert,
398 G_TYPE_STRING, subject,
399 G_TYPE_STRING, subject_alt,
400 G_TYPE_STRING, server_cert,
402 G_TYPE_BOOLEAN, &success,
405 g_object_unref (dbus_proxy);
407 if (g_error != NULL) {
408 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,