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>
35 #include <dbus/dbus-glib.h>
36 #include <dbus/dbus.h>
38 #include "libmoonshot.h"
40 #define MOONSHOT_DBUS_NAME "org.janet.Moonshot"
41 #define MOONSHOT_DBUS_PATH "/org/janet/moonshot"
43 /* This library is overly complicated currently due to the requirement
44 * that it work on Debian Squeeze - this has GLib 2.24 which requires us
45 * to use dbus-glib instead of GDBus. If/when this requirement is
46 * dropped the DBus version of the library can be greatly simplified.
52 char *server_certificate_hash;
54 char *subject_name_constraint;
55 char *subject_alt_name_constraint;
56 } MoonshotIdentityData;
58 static MoonshotIdentityData *moonshot_identity_data_new ()
60 return g_slice_new (MoonshotIdentityData);
63 static void moonshot_identity_data_free (void *data)
65 g_slice_free (MoonshotIdentityData, data);
68 static DBusGProxy *moonshot_dbus_proxy = NULL;
70 GQuark moonshot_error_quark (void)
72 return g_quark_from_static_string ("moonshot-error-quark");
75 static DBusGProxy *dbus_connect (GError **g_error)
77 DBusConnection *connection;
79 DBusGConnection *g_connection;
81 dbus_bool_t name_has_owner;
83 g_return_val_if_fail (*g_error == NULL, NULL);
85 dbus_error_init (&dbus_error);
87 /* Check for moonshot server and start the service if possible. We use
88 * libdbus here because dbus-glib doesn't handle autostarting the service.
89 * If/when we move to GDBus this code can become a one-liner.
92 connection = dbus_bus_get (DBUS_BUS_SESSION, &dbus_error);
94 if (dbus_error_is_set (&dbus_error)) {
95 *g_error = g_error_new (MOONSHOT_ERROR,
96 MOONSHOT_ERROR_DBUS_ERROR,
99 dbus_error_free (&dbus_error);
103 name_has_owner = dbus_bus_name_has_owner (connection,
107 if (dbus_error_is_set (&dbus_error)) {
108 *g_error = g_error_new (MOONSHOT_ERROR,
109 MOONSHOT_ERROR_DBUS_ERROR,
113 dbus_error_free (&dbus_error);
117 if (! name_has_owner) {
118 dbus_bus_start_service_by_name (connection,
124 if (dbus_error_is_set (&dbus_error)) {
125 if (strcmp (dbus_error.name + 27, "ServiceUnknown") == 0) {
126 /* Missing .service file; the moonshot-ui install is broken */
127 *g_error = g_error_new (MOONSHOT_ERROR,
128 MOONSHOT_ERROR_SERVICE_NOT_FOUND,
129 "The Moonshot service was not found. "
130 "Please make sure that moonshot-ui is "
131 "correctly installed.");
133 *g_error = g_error_new (MOONSHOT_ERROR,
134 MOONSHOT_ERROR_DBUS_ERROR,
138 dbus_error_free (&dbus_error);
143 /* Now the service should be running */
145 g_connection = dbus_g_bus_get (DBUS_BUS_SESSION, g_error);
147 if (*g_error != NULL)
150 g_proxy = dbus_g_proxy_new_for_name_owner (g_connection,
159 static void dbus_call_complete_cb (DBusGProxy *proxy,
160 DBusGProxyCall *call_id,
163 GError *error = NULL;
164 GSimpleAsyncResult *token;
165 MoonshotIdentityData *identity_data;
168 token = G_SIMPLE_ASYNC_RESULT (user_data);
169 identity_data = moonshot_identity_data_new ();
171 dbus_g_proxy_end_call (moonshot_dbus_proxy,
174 G_TYPE_STRING, &identity_data->nai,
175 G_TYPE_STRING, &identity_data->password,
176 G_TYPE_STRING, &identity_data->server_certificate_hash,
177 G_TYPE_STRING, &identity_data->ca_certificate,
178 G_TYPE_STRING, &identity_data->subject_name_constraint,
179 G_TYPE_STRING, &identity_data->subject_alt_name_constraint,
180 G_TYPE_BOOLEAN, &success,
184 g_simple_async_result_set_from_error (token, error);
187 if (success == FALSE) {
188 error = g_error_new (MOONSHOT_ERROR,
189 MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
190 "No matching identity was available");
191 g_simple_async_result_set_from_error (token, error);
192 g_error_free (error);
195 g_simple_async_result_set_op_res_gpointer (token,
197 moonshot_identity_data_free);
200 g_simple_async_result_complete (token);
201 g_object_unref (token);
205 * moonshot_get_identity:
206 * @cancellable: A #GCancellable, or %NULL.
207 * @callback: A #GAsyncReadyCallback, which will be called when the
208 * operation completes, fails or is cancelled.
209 * @user_data: Data to pass to @callback
210 * @nai: Name and issuer constraint for the required identity, or %NULL.
211 * @password: Password for the identity, or %NULL.
212 * @service: Service constraint for the required identity, or %NULL.
214 * This function initiates a call to the Moonshot server to request an ID card.
215 * The server will be activated if it is not already running. The user interface
216 * will be displayed if there is more than one matching identity and the user
217 * will be asked to select one.
219 * When an identity has been selected, or the operation fails or is cancelled,
220 * @callback will be run.
222 * Note that the actual IPC call may not be made until control returns to the
225 void moonshot_get_identity (GCancellable *cancellable,
226 GAsyncReadyCallback callback,
229 const char *password,
232 DBusGProxyCall *call_id;
233 GSimpleAsyncResult *result;
234 GError *error = NULL;
236 if (moonshot_dbus_proxy == NULL)
237 moonshot_dbus_proxy = dbus_connect (&error);
239 if (moonshot_dbus_proxy == NULL) {
240 result = g_simple_async_result_new (NULL,
243 moonshot_get_identity);
244 g_simple_async_result_set_from_error (result, error);
245 g_simple_async_result_complete_in_idle (result);
246 g_error_free (error);
250 g_return_if_fail (DBUS_IS_G_PROXY (moonshot_dbus_proxy));
252 result = g_simple_async_result_new (NULL,
255 moonshot_get_identity);
257 call_id = dbus_g_proxy_begin_call (moonshot_dbus_proxy,
259 dbus_call_complete_cb,
262 G_TYPE_STRING, password,
263 G_TYPE_STRING, service);
267 * moonshot_get_identity_finish:
268 * @result: The #GAsyncResult which was passed to your callback.
269 * @nai: A pointer to a string which receives the name and issuer of the
271 * @password: A pointer to a string which receives the password.
272 * @server_certificate_hash: Receives a hash of the identity server's
273 * certificate, or %NULL.
274 * @ca_certificate: The CA certificate, if @server_certificate_hash was %NULL.
275 * @subject_name_constraint: Set if @ca_certificate is set, otherwise %NULL.
276 * @subject_alt_name_constraint: Set if @ca_certificate is set, otherwise %NULL.
277 * @error: Return location for an error, or %NULL.
279 * Gets the details of the identity card that was selected, if any.
281 * There are two types of trust anchor that may be returned. If
282 * @server_certificate_hash is non-empty, the remaining parameters will be
283 * empty. Otherwise, the @ca_certificate parameter and the subject name
284 * constraints will be returned.
286 * Return value: %TRUE if an identity was successfully selected, %FALSE on
289 gboolean moonshot_get_identity_finish (GAsyncResult *result,
292 char **server_certificate_hash,
293 char **ca_certificate,
294 char **subject_name_constraint,
295 char **subject_alt_name_constraint,
298 MoonshotIdentityData *identity;
300 g_return_val_if_fail (g_simple_async_result_is_valid (result,
302 moonshot_get_identity),
305 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
308 identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
310 *nai = identity->nai;
311 *password = identity->password;
312 *server_certificate_hash = identity->server_certificate_hash;
313 *ca_certificate = identity->ca_certificate;
314 *subject_name_constraint = identity->subject_name_constraint;
315 *subject_alt_name_constraint = identity->subject_alt_name_constraint;
322 * Returns the default identity - most recently used.
324 * @param nai_out NAI stored in the ID card
325 * @param password_out Password stored in the ID card
327 * @return true on success, false if no identities are stored