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>
40 #include <dbus/dbus-glib.h>
41 #include <dbus/dbus.h>
42 #include <dbus/dbus-glib-lowlevel.h>
43 #include <glib/gspawn.h>
46 #include "libmoonshot.h"
47 #include "libmoonshot-common.h"
50 #define INFINITE_TIMEOUT 10*24*60*60*1000
52 #define MOONSHOT_DBUS_NAME "org.janet.Moonshot"
53 #define MOONSHOT_DBUS_PATH "/org/janet/moonshot"
55 /* This library is overly complicated currently due to the requirement
56 * that it work on Debian Squeeze - this has GLib 2.24 which requires us
57 * to use dbus-glib instead of GDBus. If/when this requirement is
58 * dropped the DBus version of the library can be greatly simplified.
61 /* Note that ideally this library would not depend on GLib. This would be
62 * possible using libdbus directly and running our own message loop while
66 void moonshot_free (void *data)
70 static char *moonshot_launch_argv[] = {
71 MOONSHOT_LAUNCH_SCRIPT, NULL
74 static DBusGConnection *dbus_launch_moonshot()
76 DBusGConnection *connection = NULL;
80 gint fd_stdin = -1, fd_stdout = -1;
82 dbus_error_init(&dbus_error);
83 char dbus_address[1024];
85 if (g_spawn_async_with_pipes( NULL /*cwd*/,
86 moonshot_launch_argv, NULL /*environ*/,
87 0 /*flags*/, NULL /*setup*/, NULL,
88 &child_pid, &fd_stdin, &fd_stdout,
89 NULL /*stderr*/, NULL /*error*/) == 0 ) {
93 addresslen = read( fd_stdout, dbus_address, sizeof dbus_address);
95 /* we require at least 2 octets of address because we trim the newline*/
96 if (addresslen <= 1) {
97 fail: dbus_error_free(&dbus_error);
98 if (connection != NULL)
99 dbus_g_connection_unref(connection);
101 g_spawn_close_pid(child_pid);
104 dbus_address[addresslen-1] = '\0';
105 connection = dbus_g_connection_open(dbus_address, &error);
110 if (!dbus_bus_register(dbus_g_connection_get_connection(connection),
116 static int is_setid()
119 if ((getuid() != geteuid()) ||
120 (getgid() != getegid())) {
127 static DBusGProxy *dbus_connect (MoonshotError **error)
129 DBusConnection *dbconnection;
130 DBusError dbus_error;
131 DBusGConnection *connection;
133 GError *g_error = NULL;
134 dbus_bool_t name_has_owner;
136 g_return_val_if_fail (*error == NULL, NULL);
138 dbus_error_init (&dbus_error);
140 /* Check for moonshot server and start the service if possible. We use
141 * libdbus here because dbus-glib doesn't handle autostarting the service.
142 * If/when we move to GDBus this code can become a one-liner.
146 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
147 "Cannot use IPC while setid");
151 if (getenv("DISPLAY")==NULL) {
152 connection = dbus_launch_moonshot();
153 if (connection == NULL) {
154 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
155 "Headless dbus launch failed");
161 connection = dbus_g_bus_get (DBUS_BUS_SESSION, &g_error);
163 if (g_error_matches(g_error, DBUS_GERROR, DBUS_GERROR_NOT_SUPPORTED)) {
164 /*Generally this means autolaunch failed because probably DISPLAY is unset*/
165 connection = dbus_launch_moonshot();
166 if (connection != NULL) {
167 g_error_free(g_error);
171 if (g_error != NULL) {
172 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
175 g_error_free (g_error);
181 dbconnection = dbus_g_connection_get_connection(connection);
182 name_has_owner = dbus_bus_name_has_owner (dbconnection,
186 if (dbus_error_is_set (&dbus_error)) {
187 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
190 dbus_error_free (&dbus_error);
194 if (! name_has_owner) {
195 dbus_bus_start_service_by_name (dbconnection,
201 if (dbus_error_is_set (&dbus_error)) {
202 if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
203 /* Missing .service file; the moonshot-ui install is broken */
204 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
205 "The Moonshot service was not found. "
206 "Please make sure that moonshot-ui is "
207 "correctly installed.");
209 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
213 dbus_error_free (&dbus_error);
218 /* Now the service should be running */
221 g_proxy = dbus_g_proxy_new_for_name_owner (connection,
227 if (g_error != NULL) {
228 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
231 g_error_free (g_error);
238 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
240 static DBusGProxy *dbus_proxy = NULL;
241 static GStaticMutex init_lock = G_STATIC_MUTEX_INIT;
243 g_static_mutex_lock (&init_lock);
245 if (dbus_proxy == NULL) {
246 /* Make sure GObject is initialised, in case we are the only user
247 * of GObject in the process
250 dbus_proxy = dbus_connect (error);
253 if (dbus_proxy != NULL)
254 g_object_ref (dbus_proxy);
256 g_static_mutex_unlock (&init_lock);
261 int moonshot_get_identity (const char *nai,
262 const char *password,
266 char **server_certificate_hash_out,
267 char **ca_certificate_out,
268 char **subject_name_constraint_out,
269 char **subject_alt_name_constraint_out,
270 MoonshotError **error)
272 GError *g_error = NULL;
273 DBusGProxy *dbus_proxy;
276 dbus_proxy = get_dbus_proxy (error);
281 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
283 dbus_g_proxy_call_with_timeout (dbus_proxy,
288 G_TYPE_STRING, password,
289 G_TYPE_STRING, service,
291 G_TYPE_STRING, nai_out,
292 G_TYPE_STRING, password_out,
293 G_TYPE_STRING, server_certificate_hash_out,
294 G_TYPE_STRING, ca_certificate_out,
295 G_TYPE_STRING, subject_name_constraint_out,
296 G_TYPE_STRING, subject_alt_name_constraint_out,
297 G_TYPE_BOOLEAN, &success,
300 g_object_unref (dbus_proxy);
302 if (g_error != NULL) {
303 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
308 if (success == FALSE) {
309 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
310 "No identity was returned by the Moonshot "
318 int moonshot_get_default_identity (char **nai_out,
320 char **server_certificate_hash_out,
321 char **ca_certificate_out,
322 char **subject_name_constraint_out,
323 char **subject_alt_name_constraint_out,
324 MoonshotError **error)
326 GError *g_error = NULL;
327 DBusGProxy *dbus_proxy;
330 dbus_proxy = get_dbus_proxy (error);
335 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
337 dbus_g_proxy_call_with_timeout (dbus_proxy,
338 "GetDefaultIdentity",
342 G_TYPE_STRING, nai_out,
343 G_TYPE_STRING, password_out,
344 G_TYPE_STRING, server_certificate_hash_out,
345 G_TYPE_STRING, ca_certificate_out,
346 G_TYPE_STRING, subject_name_constraint_out,
347 G_TYPE_STRING, subject_alt_name_constraint_out,
348 G_TYPE_BOOLEAN, &success,
351 g_object_unref (dbus_proxy);
353 if (g_error != NULL) {
354 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
359 if (success == FALSE) {
360 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
361 "No identity was returned by the Moonshot "
369 int moonshot_install_id_card (const char *display_name,
370 const char *user_name,
371 const char *password,
373 char *rules_patterns[],
374 int rules_patterns_length,
375 char *rules_always_confirm[],
376 int rules_always_confirm_length,
381 const char *subject_alt,
382 const char *server_cert,
383 int force_flat_file_store,
384 MoonshotError **error)
386 GError *g_error = NULL;
387 DBusGProxy *dbus_proxy;
390 const char **rules_patterns_strv,
391 **rules_always_confirm_strv,
394 dbus_proxy = get_dbus_proxy (error);
399 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
400 g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length, FALSE);
402 /* Marshall array and struct parameters for DBus */
403 rules_patterns_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
404 rules_always_confirm_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
405 services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
407 for (i = 0; i < rules_patterns_length; i ++) {
408 rules_patterns_strv[i] = rules_patterns[i];
409 rules_always_confirm_strv[i] = rules_always_confirm[i];
412 for (i = 0; i < services_length; i ++)
413 services_strv[i] = services[i];
415 rules_patterns_strv[rules_patterns_length] = NULL;
416 rules_always_confirm_strv[rules_patterns_length] = NULL;
417 services_strv[services_length] = NULL;
419 dbus_g_proxy_call (dbus_proxy,
422 G_TYPE_STRING, display_name,
423 G_TYPE_STRING, user_name,
424 G_TYPE_STRING, password,
425 G_TYPE_STRING, realm,
426 G_TYPE_STRV, rules_patterns_strv,
427 G_TYPE_STRV, rules_always_confirm_strv,
428 G_TYPE_STRV, services_strv,
429 G_TYPE_STRING, ca_cert,
430 G_TYPE_STRING, subject,
431 G_TYPE_STRING, subject_alt,
432 G_TYPE_STRING, server_cert,
433 G_TYPE_INT, force_flat_file_store,
435 G_TYPE_BOOLEAN, &success,
438 g_object_unref (dbus_proxy);
439 g_free(rules_patterns_strv);
440 g_free(rules_always_confirm_strv);
441 g_free(services_strv);
443 if (g_error != NULL) {
444 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
452 int moonshot_confirm_ca_certificate (const char *identity_name,
454 const unsigned char *ca_hash,
456 MoonshotError **error)
458 GError *g_error = NULL;
462 DBusGProxy *dbus_proxy = get_dbus_proxy (error);
466 if (*error != NULL) {
470 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
472 /* Convert hash byte array to string */
474 for (i = 0; i < hash_len; i++) {
475 sprintf(&(hash_str[out]), "%02X", ca_hash[i]);
479 dbus_g_proxy_call_with_timeout (dbus_proxy,
480 "ConfirmCaCertificate",
483 G_TYPE_STRING, identity_name,
484 G_TYPE_STRING, realm,
485 G_TYPE_STRING, hash_str,
487 G_TYPE_INT, &confirmed,
488 G_TYPE_BOOLEAN, &success,
491 g_object_unref (dbus_proxy);
493 if (g_error != NULL) {
494 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
499 return (int) confirmed;