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>
39 #include <dbus/dbus-glib.h>
40 #include <dbus/dbus.h>
41 #include <dbus/dbus-glib-lowlevel.h>
42 #include <glib/gspawn.h>
45 #include "libmoonshot.h"
46 #include "libmoonshot-common.h"
49 #define INFINITE_TIMEOUT 10*24*60*60*1000
51 #define MOONSHOT_DBUS_NAME "org.janet.Moonshot"
52 #define MOONSHOT_DBUS_PATH "/org/janet/moonshot"
54 /* This library is overly complicated currently due to the requirement
55 * that it work on Debian Squeeze - this has GLib 2.24 which requires us
56 * to use dbus-glib instead of GDBus. If/when this requirement is
57 * dropped the DBus version of the library can be greatly simplified.
60 /* Note that ideally this library would not depend on GLib. This would be
61 * possible using libdbus directly and running our own message loop while
65 void moonshot_free (void *data)
69 static char *moonshot_launch_argv[] = {
70 MOONSHOT_LAUNCH_SCRIPT, NULL
73 static DBusGConnection *dbus_launch_moonshot()
75 DBusGConnection *connection = NULL;
79 gint fd_stdin = -1, fd_stdout = -1;
81 dbus_error_init(&dbus_error);
82 char dbus_address[1024];
84 if (g_spawn_async_with_pipes( NULL /*cwd*/,
85 moonshot_launch_argv, NULL /*environ*/,
86 0 /*flags*/, NULL /*setup*/, NULL,
87 &child_pid, &fd_stdin, &fd_stdout,
88 NULL /*stderr*/, NULL /*error*/) == 0 ) {
92 addresslen = read( fd_stdout, dbus_address, sizeof dbus_address);
94 /* we require at least 2 octets of address because we trim the newline*/
95 if (addresslen <= 1) {
96 fail: dbus_error_free(&dbus_error);
97 if (connection != NULL)
98 dbus_g_connection_unref(connection);
100 g_spawn_close_pid(child_pid);
103 dbus_address[addresslen-1] = '\0';
104 connection = dbus_g_connection_open(dbus_address, &error);
109 if (!dbus_bus_register(dbus_g_connection_get_connection(connection),
115 static int is_setid()
118 if ((getuid() != geteuid()) ||
119 (getgid() != getegid())) {
126 static DBusGProxy *dbus_connect (MoonshotError **error)
128 DBusConnection *dbconnection;
129 DBusError dbus_error;
130 DBusGConnection *connection;
132 GError *g_error = NULL;
133 dbus_bool_t name_has_owner;
135 g_return_val_if_fail (*error == NULL, NULL);
137 dbus_error_init (&dbus_error);
139 /* Check for moonshot server and start the service if possible. We use
140 * libdbus here because dbus-glib doesn't handle autostarting the service.
141 * If/when we move to GDBus this code can become a one-liner.
145 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
146 "Cannot use IPC while setid");
150 if (getenv("DISPLAY")==NULL) {
151 connection = dbus_launch_moonshot();
152 if (connection == NULL) {
153 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
154 "Headless dbus launch failed");
160 connection = dbus_g_bus_get (DBUS_BUS_SESSION, &g_error);
162 if (g_error_matches(g_error, DBUS_GERROR, DBUS_GERROR_NOT_SUPPORTED)) {
163 /*Generally this means autolaunch failed because probably DISPLAY is unset*/
164 connection = dbus_launch_moonshot();
165 if (connection != NULL) {
166 g_error_free(g_error);
170 if (g_error != NULL) {
171 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
174 g_error_free (g_error);
180 dbconnection = dbus_g_connection_get_connection(connection);
181 name_has_owner = dbus_bus_name_has_owner (dbconnection,
185 if (dbus_error_is_set (&dbus_error)) {
186 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
189 dbus_error_free (&dbus_error);
193 if (! name_has_owner) {
194 dbus_bus_start_service_by_name (dbconnection,
200 if (dbus_error_is_set (&dbus_error)) {
201 if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
202 /* Missing .service file; the moonshot-ui install is broken */
203 *error = moonshot_error_new (MOONSHOT_ERROR_UNABLE_TO_START_SERVICE,
204 "The Moonshot service was not found. "
205 "Please make sure that moonshot-ui is "
206 "correctly installed.");
208 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
212 dbus_error_free (&dbus_error);
217 /* Now the service should be running */
220 g_proxy = dbus_g_proxy_new_for_name_owner (connection,
226 if (g_error != NULL) {
227 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
230 g_error_free (g_error);
237 static DBusGProxy *get_dbus_proxy (MoonshotError **error)
239 static DBusGProxy *dbus_proxy = NULL;
240 static GStaticMutex init_lock = G_STATIC_MUTEX_INIT;
242 g_static_mutex_lock (&init_lock);
244 if (dbus_proxy == NULL) {
245 /* Make sure GObject is initialised, in case we are the only user
246 * of GObject in the process
249 dbus_proxy = dbus_connect (error);
252 if (dbus_proxy != NULL)
253 g_object_ref (dbus_proxy);
255 g_static_mutex_unlock (&init_lock);
260 int moonshot_get_identity (const char *nai,
261 const char *password,
265 char **server_certificate_hash_out,
266 char **ca_certificate_out,
267 char **subject_name_constraint_out,
268 char **subject_alt_name_constraint_out,
269 MoonshotError **error)
271 GError *g_error = NULL;
272 DBusGProxy *dbus_proxy;
275 dbus_proxy = get_dbus_proxy (error);
280 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
282 dbus_g_proxy_call_with_timeout (dbus_proxy,
287 G_TYPE_STRING, password,
288 G_TYPE_STRING, service,
290 G_TYPE_STRING, nai_out,
291 G_TYPE_STRING, password_out,
292 G_TYPE_STRING, server_certificate_hash_out,
293 G_TYPE_STRING, ca_certificate_out,
294 G_TYPE_STRING, subject_name_constraint_out,
295 G_TYPE_STRING, subject_alt_name_constraint_out,
296 G_TYPE_BOOLEAN, &success,
299 g_object_unref (dbus_proxy);
301 if (g_error != NULL) {
302 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
307 if (success == FALSE) {
308 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
309 "No identity was returned by the Moonshot "
317 int moonshot_get_default_identity (char **nai_out,
319 char **server_certificate_hash_out,
320 char **ca_certificate_out,
321 char **subject_name_constraint_out,
322 char **subject_alt_name_constraint_out,
323 MoonshotError **error)
325 GError *g_error = NULL;
326 DBusGProxy *dbus_proxy;
329 dbus_proxy = get_dbus_proxy (error);
334 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
336 dbus_g_proxy_call_with_timeout (dbus_proxy,
337 "GetDefaultIdentity",
341 G_TYPE_STRING, nai_out,
342 G_TYPE_STRING, password_out,
343 G_TYPE_STRING, server_certificate_hash_out,
344 G_TYPE_STRING, ca_certificate_out,
345 G_TYPE_STRING, subject_name_constraint_out,
346 G_TYPE_STRING, subject_alt_name_constraint_out,
347 G_TYPE_BOOLEAN, &success,
350 g_object_unref (dbus_proxy);
352 if (g_error != NULL) {
353 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
358 if (success == FALSE) {
359 *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
360 "No identity was returned by the Moonshot "
368 int moonshot_install_id_card (const char *display_name,
369 const char *user_name,
370 const char *password,
372 char *rules_patterns[],
373 int rules_patterns_length,
374 char *rules_always_confirm[],
375 int rules_always_confirm_length,
380 const char *subject_alt,
381 const char *server_cert,
382 int force_flat_file_store,
383 MoonshotError **error)
385 GError *g_error = NULL;
386 DBusGProxy *dbus_proxy;
389 const char **rules_patterns_strv,
390 **rules_always_confirm_strv,
393 dbus_proxy = get_dbus_proxy (error);
398 g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
399 g_return_val_if_fail (rules_patterns_length == rules_always_confirm_length, FALSE);
401 /* Marshall array and struct parameters for DBus */
402 rules_patterns_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
403 rules_always_confirm_strv = g_malloc ((rules_patterns_length + 1) * sizeof (const char *));
404 services_strv = g_malloc ((services_length + 1) * sizeof (const char *));
406 for (i = 0; i < rules_patterns_length; i ++) {
407 rules_patterns_strv[i] = rules_patterns[i];
408 rules_always_confirm_strv[i] = rules_always_confirm[i];
411 for (i = 0; i < services_length; i ++)
412 services_strv[i] = services[i];
414 rules_patterns_strv[rules_patterns_length] = NULL;
415 rules_always_confirm_strv[rules_patterns_length] = NULL;
416 services_strv[services_length] = NULL;
418 dbus_g_proxy_call (dbus_proxy,
421 G_TYPE_STRING, display_name,
422 G_TYPE_STRING, user_name,
423 G_TYPE_STRING, password,
424 G_TYPE_STRING, realm,
425 G_TYPE_STRV, rules_patterns_strv,
426 G_TYPE_STRV, rules_always_confirm_strv,
427 G_TYPE_STRV, services_strv,
428 G_TYPE_STRING, ca_cert,
429 G_TYPE_STRING, subject,
430 G_TYPE_STRING, subject_alt,
431 G_TYPE_STRING, server_cert,
432 G_TYPE_INT, force_flat_file_store,
434 G_TYPE_BOOLEAN, &success,
437 g_object_unref (dbus_proxy);
439 if (g_error != NULL) {
440 *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,