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),
114 static int is_setid()
117 if ((getuid() != geteuid()) ||
118 (getgid() != getegid())) {
125 static DBusGProxy *dbus_connect (MoonshotError **error)
127 DBusConnection *dbconnection;
128 DBusError dbus_error;
129 DBusGConnection *connection;
131 GError *g_error = NULL;
132 dbus_bool_t name_has_owner;
134 g_return_val_if_fail (*error == NULL, NULL);
136 dbus_error_init (&dbus_error);
138 /* Check for moonshot server and start the service if possible. We use
139 * libdbus here because dbus-glib doesn't handle autostarting the service.
140 * If/when we move to GDBus this code can become a one-liner.
144 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
145 "Cannot use IPC while setid");
149 connection = dbus_g_bus_get (DBUS_BUS_SESSION, &g_error);
151 if (g_error_matches(g_error, DBUS_GERROR, DBUS_GERROR_NOT_SUPPORTED)) {
152 /*Generally this means autolaunch failed because probably DISPLAY is unset*/
153 connection = dbus_launch_moonshot();
154 if (connection != NULL) {
155 g_error_free(g_error);
160 if (g_error != NULL) {
161 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
164 g_error_free (g_error);
168 dbconnection = dbus_g_connection_get_connection(connection);
169 name_has_owner = dbus_bus_name_has_owner (dbconnection,
173 if (dbus_error_is_set (&dbus_error)) {
174 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
177 dbus_error_free (&dbus_error);
181 if (! name_has_owner) {
182 dbus_bus_start_service_by_name (dbconnection,
188 if (dbus_error_is_set (&dbus_error)) {
189 if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
190 /* Missing .service file; the moonshot-ui install is broken */
191 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
192 "The Moonshot service was not found. "
193 "Please make sure that moonshot-ui is "
194 "correctly installed.");
196 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
200 dbus_error_free (&dbus_error);
205 /* Now the service should be running */
208 g_proxy = dbus_g_proxy_new_for_name_owner (connection,
214 if (g_error != NULL) {
215 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
218 g_error_free (g_error);
225 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
227 static DBusGProxy *dbus_proxy = NULL;
228 static GStaticMutex init_lock = G_STATIC_MUTEX_INIT;
230 g_static_mutex_lock (&init_lock);
232 if (dbus_proxy == NULL) {
233 /* Make sure GObject is initialised, in case we are the only user
234 * of GObject in the process
237 dbus_proxy = dbus_connect (error);
240 if (dbus_proxy != NULL)
241 g_object_ref (dbus_proxy);
243 g_static_mutex_unlock (&init_lock);
248 int moonshot_get_identity (const char *nai,
249 const char *password,
253 char **server_certificate_hash_out,
254 char **ca_certificate_out,
255 char **subject_name_constraint_out,
256 char **subject_alt_name_constraint_out,
257 MoonshotError **error)
259 GError *g_error = NULL;
260 DBusGProxy *dbus_proxy;
263 dbus_proxy = get_dbus_proxy (error);
268 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
270 dbus_g_proxy_call_with_timeout (dbus_proxy,
275 G_TYPE_STRING, password,
276 G_TYPE_STRING, service,
278 G_TYPE_STRING, nai_out,
279 G_TYPE_STRING, password_out,
280 G_TYPE_STRING, server_certificate_hash_out,
281 G_TYPE_STRING, ca_certificate_out,
282 G_TYPE_STRING, subject_name_constraint_out,
283 G_TYPE_STRING, subject_alt_name_constraint_out,
284 G_TYPE_BOOLEAN, &success,
287 g_object_unref (dbus_proxy);
289 if (g_error != NULL) {
290 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
295 if (success == FALSE) {
296 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
297 "No identity was returned by the Moonshot "
305 int moonshot_get_default_identity (char **nai_out,
307 char **server_certificate_hash_out,
308 char **ca_certificate_out,
309 char **subject_name_constraint_out,
310 char **subject_alt_name_constraint_out,
311 MoonshotError **error)
313 GError *g_error = NULL;
314 DBusGProxy *dbus_proxy;
317 dbus_proxy = get_dbus_proxy (error);
322 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
324 dbus_g_proxy_call_with_timeout (dbus_proxy,
325 "GetDefaultIdentity",
329 G_TYPE_STRING, nai_out,
330 G_TYPE_STRING, password_out,
331 G_TYPE_STRING, server_certificate_hash_out,
332 G_TYPE_STRING, ca_certificate_out,
333 G_TYPE_STRING, subject_name_constraint_out,
334 G_TYPE_STRING, subject_alt_name_constraint_out,
335 G_TYPE_BOOLEAN, &success,
338 g_object_unref (dbus_proxy);
340 if (g_error != NULL) {
341 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
346 if (success == FALSE) {
347 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
348 "No identity was returned by the Moonshot "
356 int moonshot_install_id_card (const char *display_name,
357 const char *user_name,
358 const char *password,
360 char *rules_patterns[],
361 int rules_patterns_length,
362 char *rules_always_confirm[],
363 int rules_always_confirm_length,
368 const char *subject_alt,
369 const char *server_cert,
370 int force_flat_file_store,
371 MoonshotError **error)
373 GError *g_error = NULL;
374 DBusGProxy *dbus_proxy;
377 const char **rules_patterns_strv,
378 **rules_always_confirm_strv,
381 dbus_proxy = get_dbus_proxy (error);
386 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
387 g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length, FALSE);
389 /* Marshall array and struct parameters for DBus */
390 rules_patterns_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
391 rules_always_confirm_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
392 services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
394 for (i = 0; i < rules_patterns_length; i ++) {
395 rules_patterns_strv[i] = rules_patterns[i];
396 rules_always_confirm_strv[i] = rules_always_confirm[i];
399 for (i = 0; i < services_length; i ++)
400 services_strv[i] = services[i];
402 rules_patterns_strv[rules_patterns_length] = NULL;
403 rules_always_confirm_strv[rules_patterns_length] = NULL;
404 services_strv[services_length] = NULL;
406 dbus_g_proxy_call (dbus_proxy,
409 G_TYPE_STRING, display_name,
410 G_TYPE_STRING, user_name,
411 G_TYPE_STRING, password,
412 G_TYPE_STRING, realm,
413 G_TYPE_STRV, rules_patterns_strv,
414 G_TYPE_STRV, rules_always_confirm_strv,
415 G_TYPE_STRV, services_strv,
416 G_TYPE_STRING, ca_cert,
417 G_TYPE_STRING, subject,
418 G_TYPE_STRING, subject_alt,
419 G_TYPE_STRING, server_cert,
420 G_TYPE_INT, force_flat_file_store,
422 G_TYPE_BOOLEAN, &success,
425 g_object_unref (dbus_proxy);
427 if (g_error != NULL) {
428 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,