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 ) {
88 addresslen = read( fd_stdout, dbus_address, sizeof dbus_address);
89 /* we require at least 2 octets of address because we trim the newline*/
90 if (addresslen <= 1) {
91 fail: close(fd_stdin);
93 g_spawn_close_pid(child_pid);
96 dbus_error_init(&dbus_error);
97 dbus_address[addresslen-1] = '\0';
98 connection = dbus_connection_open(dbus_address, &dbus_error);
99 if (dbus_error_is_set(&dbus_error)) {
100 dbus_error_free(&dbus_error);
102 } else return connection;
106 static DBusGProxy *dbus_connect (MoonshotError **error)
108 DBusConnection *connection;
109 DBusError dbus_error;
110 DBusGConnection *g_connection;
112 GError *g_error = NULL;
113 dbus_bool_t name_has_owner;
115 g_return_val_if_fail (*error == NULL, NULL);
117 dbus_error_init (&dbus_error);
119 /* Check for moonshot server and start the service if possible. We use
120 * libdbus here because dbus-glib doesn't handle autostarting the service.
121 * If/when we move to GDBus this code can become a one-liner.
124 connection = dbus_bus_get (DBUS_BUS_SESSION, &dbus_error);
126 if (dbus_error_has_name(&dbus_error, DBUS_ERROR_NOT_SUPPORTED)) {
127 /*Generally this means autolaunch failed because probably DISPLAY is unset*/
128 connection = dbus_launch_moonshot();
129 if (connection != NULL) {
130 dbus_error_free(&dbus_error);
131 dbus_error_init(&dbus_error);
135 if (dbus_error_is_set (&dbus_error)) {
136 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
139 dbus_error_free (&dbus_error);
143 name_has_owner = dbus_bus_name_has_owner (connection,
147 if (dbus_error_is_set (&dbus_error)) {
148 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
151 dbus_error_free (&dbus_error);
155 if (! name_has_owner) {
156 dbus_bus_start_service_by_name (connection,
162 if (dbus_error_is_set (&dbus_error)) {
163 if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
164 /* Missing .service file; the moonshot-ui install is broken */
165 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
166 "The Moonshot service was not found. "
167 "Please make sure that moonshot-ui is "
168 "correctly installed.");
170 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
174 dbus_error_free (&dbus_error);
179 /* Now the service should be running */
182 g_connection = dbus_connection_get_g_connection(connection);
183 assert (g_connection != NULL);
184 g_proxy = dbus_g_proxy_new_for_name_owner (g_connection,
190 if (g_error != NULL) {
191 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
194 g_error_free (g_error);
201 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
203 static DBusGProxy *dbus_proxy = NULL;
204 static GStaticMutex init_lock = G_STATIC_MUTEX_INIT;
206 g_static_mutex_lock (&init_lock);
208 if (dbus_proxy == NULL) {
209 /* Make sure GObject is initialised, in case we are the only user
210 * of GObject in the process
213 dbus_proxy = dbus_connect (error);
216 if (dbus_proxy != NULL)
217 g_object_ref (dbus_proxy);
219 g_static_mutex_unlock (&init_lock);
224 int moonshot_get_identity (const char *nai,
225 const char *password,
229 char **server_certificate_hash_out,
230 char **ca_certificate_out,
231 char **subject_name_constraint_out,
232 char **subject_alt_name_constraint_out,
233 MoonshotError **error)
235 GError *g_error = NULL;
236 DBusGProxy *dbus_proxy;
239 dbus_proxy = get_dbus_proxy (error);
244 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
246 dbus_g_proxy_call_with_timeout (dbus_proxy,
251 G_TYPE_STRING, password,
252 G_TYPE_STRING, service,
254 G_TYPE_STRING, nai_out,
255 G_TYPE_STRING, password_out,
256 G_TYPE_STRING, server_certificate_hash_out,
257 G_TYPE_STRING, ca_certificate_out,
258 G_TYPE_STRING, subject_name_constraint_out,
259 G_TYPE_STRING, subject_alt_name_constraint_out,
260 G_TYPE_BOOLEAN, &success,
263 g_object_unref (dbus_proxy);
265 if (g_error != NULL) {
266 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
271 if (success == FALSE) {
272 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
273 "No identity was returned by the Moonshot "
281 int moonshot_get_default_identity (char **nai_out,
283 char **server_certificate_hash_out,
284 char **ca_certificate_out,
285 char **subject_name_constraint_out,
286 char **subject_alt_name_constraint_out,
287 MoonshotError **error)
289 GError *g_error = NULL;
290 DBusGProxy *dbus_proxy;
293 dbus_proxy = get_dbus_proxy (error);
298 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
300 dbus_g_proxy_call_with_timeout (dbus_proxy,
301 "GetDefaultIdentity",
305 G_TYPE_STRING, nai_out,
306 G_TYPE_STRING, password_out,
307 G_TYPE_STRING, server_certificate_hash_out,
308 G_TYPE_STRING, ca_certificate_out,
309 G_TYPE_STRING, subject_name_constraint_out,
310 G_TYPE_STRING, subject_alt_name_constraint_out,
311 G_TYPE_BOOLEAN, &success,
314 g_object_unref (dbus_proxy);
316 if (g_error != NULL) {
317 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
322 if (success == FALSE) {
323 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
324 "No identity was returned by the Moonshot "
332 int moonshot_install_id_card (const char *display_name,
333 const char *user_name,
334 const char *password,
336 char *rules_patterns[],
337 int rules_patterns_length,
338 char *rules_always_confirm[],
339 int rules_always_confirm_length,
344 const char *subject_alt,
345 const char *server_cert,
346 MoonshotError **error)
348 GError *g_error = NULL;
349 DBusGProxy *dbus_proxy;
352 const char **rules_patterns_strv,
353 **rules_always_confirm_strv,
356 dbus_proxy = get_dbus_proxy (error);
361 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
362 g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length, FALSE);
364 /* Marshall array and struct parameters for DBus */
365 rules_patterns_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
366 rules_always_confirm_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
367 services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
369 for (i = 0; i < rules_patterns_length; i ++) {
370 rules_patterns_strv[i] = rules_patterns[i];
371 rules_always_confirm_strv[i] = rules_always_confirm[i];
374 for (i = 0; i < services_length; i ++)
375 services_strv[i] = services[i];
377 rules_patterns_strv[rules_patterns_length] = NULL;
378 rules_always_confirm_strv[rules_patterns_length] = NULL;
379 services_strv[services_length] = NULL;
381 dbus_g_proxy_call (dbus_proxy,
384 G_TYPE_STRING, display_name,
385 G_TYPE_STRING, user_name,
386 G_TYPE_STRING, password,
387 G_TYPE_STRING, realm,
388 G_TYPE_STRV, rules_patterns_strv,
389 G_TYPE_STRV, rules_always_confirm_strv,
390 G_TYPE_STRV, services_strv,
391 G_TYPE_STRING, ca_cert,
392 G_TYPE_STRING, subject,
393 G_TYPE_STRING, subject_alt,
394 G_TYPE_STRING, server_cert,
396 G_TYPE_BOOLEAN, &success,
399 g_object_unref (dbus_proxy);
401 if (g_error != NULL) {
402 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,