Index: exo-hal/exo-hal.c
===================================================================
--- exo-hal/exo-hal.c (revision 27044)
+++ exo-hal/exo-hal.c (working copy)
@@ -99,6 +99,7 @@
HAL_ICON_VOLUME_ZIP = 0x20b00,
HAL_ICON_VOLUME_JAZ = 0x20c00,
HAL_ICON_VOLUME_FLASH_KEY = 0x20d00,
+ HAL_ICON_VOLUME_CRYPTO = 0x20e00,
HAL_ICON_DISC_CDROM = 0x30000,
HAL_ICON_DISC_CDR = HAL_ICON_DISC_CDROM + LIBHAL_VOLUME_DISC_TYPE_CDR,
@@ -180,6 +181,7 @@
{ HAL_ICON_VOLUME_ZIP, "gnome-dev-zipdisk" },
{ HAL_ICON_VOLUME_JAZ, "gnome-dev-jazdisk" },
{ HAL_ICON_VOLUME_FLASH_KEY, "gnome-dev-harddisk" }, /* TODO: gnome-dev-pendrive */
+ { HAL_ICON_VOLUME_CRYPTO, "gtk-dialog-authentication" },
{ HAL_ICON_DISC_CDROM, "gnome-dev-cdrom" },
{ HAL_ICON_DISC_CDR, "gnome-dev-disc-cdr" },
@@ -806,6 +808,11 @@
}
}
+ if (G_UNLIKELY(libhal_volume_get_fsusage(volume) == LIBHAL_VOLUME_USAGE_CRYPTO)) {
+ gchar *tmp = g_strdup_printf(_("Encrypted %s"), display_name);
+ g_free(display_name);
+ display_name = tmp;
+ }
return display_name;
#else
/* HAL is not available, impossible to figure out
@@ -857,6 +864,9 @@
if (G_UNLIKELY (icon_name != NULL))
icon_list = g_list_append (icon_list, g_strdup (icon_name));
+ if (G_UNLIKELY(libhal_volume_get_fsusage(volume) == LIBHAL_VOLUME_USAGE_CRYPTO))
+ icon_list = g_list_append(icon_list, g_strdup("gtk-dialog-authentication"));
+
/* check if we have a disc based volume */
if (libhal_volume_is_disc (volume))
{
Index: exo-mount/main.c
===================================================================
--- exo-mount/main.c (revision 27044)
+++ exo-mount/main.c (working copy)
@@ -306,12 +306,12 @@
"but kernel doesn't list the volume as mounted");
}
+#ifdef HAVE_HAL
+err0:
+#endif
/* check if we failed */
if (G_UNLIKELY (err != NULL))
{
-#ifdef HAVE_HAL
-err0:
-#endif
/* check if we should display an error dialog */
if (G_LIKELY (!opt_noui))
{
Index: exo-mount/exo-mount-hal.c
===================================================================
--- exo-mount/exo-mount-hal.c (revision 27044)
+++ exo-mount/exo-mount-hal.c (working copy)
@@ -145,8 +145,351 @@
}
+static void
+exo_prompt_update_text (GtkEditable *editable,
+ gchar *new_text,
+ gint new_text_len,
+ gint *position,
+ gpointer data)
+{
+ gchar **response = (gchar **)data;
+ if (response == NULL)
+ return;
+ g_free(*response);
+ *response = gtk_editable_get_chars(editable, 0, -1);
+}
+typedef struct _ExoDialogValidate {
+ GtkWidget *dialog;
+ gint response;
+} ExoDialogValidate;
+
+void
+exo_prompt_validate_text (GtkEntry *entry,
+ gpointer data)
+{
+ ExoDialogValidate *validate_data = (ExoDialogValidate *)data;
+ gtk_dialog_response(GTK_DIALOG(validate_data->dialog), validate_data->response);
+}
+
+static void
+exo_hal_device_removed (LibHalContext *context,
+ const gchar *udi)
+{
+ const gchar *dialog_udi;
+ GtkWidget *dialog = libhal_ctx_get_user_data (context);
+
+ /* check if the active UDI of the dialog was removed */
+ dialog_udi = g_object_get_data (G_OBJECT (dialog), "udi");
+ if (exo_str_is_equal (dialog_udi, udi))
+ {
+ /* cancel the dialog */
+ gtk_dialog_response (GTK_DIALOG (dialog), 0);
+ }
+}
+
/**
+ * exo_ask_password:
+ * @context : a #LibHalContext.
+ * @udi : the UDI of the device being added, which is watched for removal.
+ * @icon : the icon or %NULL.
+ * @title : the prompt title.
+ * @response_text : the response text.
+ * @visible : whether text typed should be visible.
+ * @default_response : Which response to return on Enter.
+ * @primary_text : the primary prompt text.
+ * @secondary_text : the secondary prompt text.
+ * @first_button_text : the first button text.
+ * @... : %NULL-terminated list of button text, response id pairs.
+ *
+ * Return value: the selected response.
+ **/
+static gint
+exo_ask_password (LibHalContext *context,
+ const gchar *udi,
+ const gchar *icon,
+ const gchar *title,
+ gchar **response_text,
+ gboolean visible,
+ gint default_response,
+ const gchar *primary_text,
+ const gchar *secondary_text,
+ const gchar *first_button_text,
+ ...)
+{
+ GtkWidget *dialog;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *entry;
+ DBusError derror;
+ va_list args;
+ gint response;
+ ExoDialogValidate validate_data;
+
+ g_return_val_if_fail (exo_hal_udi_validate (udi, -1, NULL), 0);
+ g_return_val_if_fail (context != NULL, GTK_RESPONSE_CANCEL);
+
+ /* allocate a new dialog */
+ dialog = gtk_dialog_new ();
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ g_object_set_data_full (G_OBJECT (dialog), "udi", g_strdup (udi), g_free);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 6);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 12);
+
+ /* setup the specified title */
+ if (G_LIKELY (title != NULL))
+ gtk_window_set_title (GTK_WINDOW (dialog), title);
+
+ /* setup the specified buttons */
+ if (G_LIKELY (first_button_text != NULL))
+ {
+ va_start (args, first_button_text);
+ for (response = va_arg (args, gint); first_button_text != NULL; )
+ {
+ /* insert the button */
+ gtk_dialog_add_button (GTK_DIALOG (dialog), first_button_text, response);
+ first_button_text = va_arg (args, const gchar *);
+ if (G_UNLIKELY (first_button_text == NULL))
+ break;
+ response = va_arg (args, gint);
+ }
+ va_end (args);
+ }
+
+ /* setup the hbox */
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ /* setup the specified icon */
+ if (G_LIKELY (icon != NULL))
+ {
+ /* setup an image for the icon */
+ image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.0f, 0.0f);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+ gtk_widget_show (image);
+ }
+
+ /* setup the vbox */
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+ gtk_widget_show (vbox);
+
+ /* setup the primary text */
+ label = gtk_label_new (primary_text);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* setup the secondary text */
+ if (G_LIKELY (secondary_text != NULL))
+ {
+ label = gtk_label_new (secondary_text);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+ }
+
+ entry = gtk_entry_new();
+ gtk_entry_set_visibility(GTK_ENTRY(entry), visible);
+ gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+ gtk_widget_show (entry);
+
+ /* initialize D-Bus error */
+ dbus_error_init (&derror);
+
+ /* setup HAL to watch the UDI for removal */
+ libhal_ctx_set_user_data (context, dialog);
+ libhal_ctx_set_device_removed (context, exo_hal_device_removed);
+ libhal_device_property_watch_all (context, &derror);
+
+ /* setup handler for the entered text */
+ if (response_text)
+ *response_text = NULL;
+ g_signal_connect_after(G_OBJECT(entry), "insert-text",
+ G_CALLBACK(exo_prompt_update_text),
+ (gpointer) response_text);
+ validate_data.dialog = dialog;
+ validate_data.response = default_response;
+ g_signal_connect(G_OBJECT(entry), "activate",
+ G_CALLBACK(exo_prompt_validate_text),
+ (gpointer) &validate_data);
+
+ /* run the dialog */
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ /* cleanup */
+ libhal_ctx_set_device_removed (context, NULL);
+ libhal_ctx_set_user_data (context, NULL);
+ gtk_widget_destroy (dialog);
+ dbus_error_free (&derror);
+
+ return response;
+}
+
+static gchar *
+exo_mount_install_crypto_volume (LibHalContext *context,
+ const gchar *udi,
+ LibHalVolume *volume,
+ const gchar *password,
+ gboolean *pass_error,
+ GError **error)
+{
+ gchar *plain_udi = NULL;
+ DBusMessage *msg = NULL, *reply = NULL;
+ DBusError err;
+ DBusConnection *dbus_connection = NULL;
+
+ *pass_error = FALSE;
+ msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ "org.freedesktop.Hal.Device.Volume.Crypto",
+ "Setup");
+ if (msg == NULL) {
+ g_warning ("Could not create dbus message for %s", udi);
+ goto out;
+ }
+
+ if (!dbus_message_append_args (msg,
+ DBUS_TYPE_STRING, &password,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("Could not append args to dbus message for %s", udi);
+ goto out;
+ }
+
+ dbus_error_init (&err);
+ dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
+ if (!dbus_connection) {
+ if (dbus_error_is_set (&err)) {
+ g_message ("Dbus connection failed for %s: %s : %s\n", udi, err.name, err.message);
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, err.message);
+ dbus_error_free(&err);
+ }
+ goto out;
+ }
+ if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, msg, -1, &err)) ||
+ dbus_error_is_set (&err)) {
+ g_message ("Setup failed for %s: %s : %s\n", udi, err.name, err.message);
+ if (strcmp (err.name, "org.freedesktop.Hal.Device.Volume.Crypto.SetupPasswordError") == 0) {
+ *pass_error = TRUE;
+ }
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, err.message);
+ dbus_error_free (&err);
+ goto out;
+ } else {
+ plain_udi = libhal_volume_crypto_get_clear_volume_udi (context, volume);
+ }
+
+
+out:
+ if (msg != NULL)
+ dbus_message_unref (msg);
+ if (reply != NULL)
+ dbus_message_unref (reply);
+ if (plain_udi)
+ g_clear_error(error);
+ return plain_udi;
+}
+
+static gchar *
+exo_mount_setup_crypto_volume(LibHalContext *context,
+ const gchar *udi,
+ GError **error)
+{
+ gchar *password = NULL;
+ gboolean pass_error = FALSE;
+ gint num_tries = 0;
+ gchar *plain_udi = NULL;
+ LibHalVolume *volume = NULL;
+
+ volume = libhal_volume_from_udi (context, udi);
+ g_return_val_if_fail(volume != NULL, NULL);
+ plain_udi = libhal_volume_crypto_get_clear_volume_udi (context, volume);
+ if (plain_udi != NULL) {
+ libhal_volume_free(volume);
+ return plain_udi;
+ }
+
+ for (num_tries = 0; num_tries < 3; num_tries++) {
+ gint response,len;
+ response = exo_ask_password (context, udi, "gtk-dialog-authentication", _("Encrypted volume"),
+ &password, FALSE, GTK_RESPONSE_OK,
+ pass_error? _("Wrong password.")
+ :_("This volume is encrypted."),
+ _("Please enter your password to decrypt and mount the volume."),
+ _("Ig_nore"), GTK_RESPONSE_CANCEL,
+ _("_Mount"), GTK_RESPONSE_OK,
+ NULL);
+ if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) {
+ num_tries = 3;
+ } else if (password) {
+ plain_udi = exo_mount_install_crypto_volume(context, udi, volume, password, &pass_error, error);
+ }
+ if (password) {
+ len = strlen(password);
+ memset(password, 0, len);
+ g_debug("zeroed password %p", password);
+ g_free(password);
+ }
+ if (plain_udi != NULL)
+ break;
+ }
+ return plain_udi;
+}
+
+static void
+exo_mount_teardown_crypto_volume(const gchar *udi)
+{
+ DBusMessage *msg = NULL, *reply = NULL;
+ DBusError err;
+ DBusConnection *dbus_connection = NULL;
+
+ msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ "org.freedesktop.Hal.Device.Volume.Crypto",
+ "Teardown");
+ if (msg == NULL) {
+ g_warning ("Could not create dbus message for %s", udi);
+ goto out;
+ }
+
+ if (!dbus_message_append_args (msg,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("Could not append args to dbus message for %s", udi);
+ goto out;
+ }
+
+ dbus_error_init (&err);
+ dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
+ if (!dbus_connection) {
+ if (dbus_error_is_set (&err)) {
+ g_message ("Dbus connection failed for %s: %s : %s\n", udi, err.name, err.message);
+ dbus_error_free(&err);
+ }
+ goto out;
+ }
+ if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, msg, -1, &err)) ||
+ dbus_error_is_set (&err)) {
+ g_message ("Teardown failed for %s: %s : %s\n", udi, err.name, err.message);
+ dbus_error_free (&err);
+ goto out;
+ } else {
+ g_debug("Teardown done\n");
+ }
+
+
+out:
+ if (msg != NULL)
+ dbus_message_unref (msg);
+ if (reply != NULL)
+ dbus_message_unref (reply);
+}
+/**
* exo_mount_hal_device_from_udi:
* @udi : UDI of a volume or drive.
* @error : return location for errors or %NULL.
@@ -215,9 +558,18 @@
}
/* verify that we have a mountable device here */
- for (n = 0; interfaces[n] != NULL; ++n)
+ for (n = 0; interfaces[n] != NULL; ++n) {
+ if (strcmp (interfaces[n], "org.freedesktop.Hal.Device.Volume.Crypto") == 0) {
+ gchar *plain_udi = exo_mount_setup_crypto_volume(hal_context, udi,error);
+ if (plain_udi) {
+ device = exo_mount_hal_device_from_udi(plain_udi, error);
+ libhal_free_string(plain_udi);
+ }
+ goto out;
+ }
if (strcmp (interfaces[n], "org.freedesktop.Hal.Device.Volume") == 0)
break;
+ }
if (G_UNLIKELY (interfaces[n] == NULL))
{
/* definitely not a device that we're able to mount, eject or unmount */
@@ -350,6 +702,8 @@
for (m = 0; interfaces[m] != NULL; ++m)
if (strcmp (interfaces[m], "org.freedesktop.Hal.Device.Volume") == 0)
break;
+ else if (strcmp (interfaces[m], "org.freedesktop.Hal.Device.Volume.Crypto") == 0)
+ break;
/* check if it's a usable device */
if (interfaces[m] != NULL)
@@ -547,10 +901,19 @@
DBusMessage *message;
DBusMessage *result;
DBusError derror;
+ const gchar *backing_udi = NULL;
g_return_val_if_fail (device != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* see if the udi is a crypto fs, in which case we'll have to teardown the crypto layer. */
+ backing_udi = libhal_volume_crypto_get_backing_volume_udi(device->volume);
+
+ if (backing_udi)
+ {
+ /* never eject a LUKS-encrypted device */
+ return exo_mount_hal_device_unmount(device, error);
+ }
/* allocate the D-Bus message for the "Eject" method */
message = dbus_message_new_method_call ("org.freedesktop.Hal", device->udi, "org.freedesktop.Hal.Device.Volume", "Eject");
if (G_UNLIKELY (message == NULL))
@@ -721,7 +1084,7 @@
DBUS_TYPE_STRING, &mount_point,
DBUS_TYPE_STRING, &fstype,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, n,
- DBUS_TYPE_INVALID))
+ DBUS_TYPE_INVALID))
{
dbus_message_unref (message);
goto oom;
@@ -894,10 +1257,14 @@
DBusMessage *message;
DBusMessage *result;
DBusError derror;
+ const gchar *backing_udi = NULL;
g_return_val_if_fail (device != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* see if the udi is a crypto fs, in which case we'll have to teardown the crypto layer. */
+ backing_udi = libhal_volume_crypto_get_backing_volume_udi(device->volume);
+
/* allocate the D-Bus message for the "Unmount" method */
message = dbus_message_new_method_call ("org.freedesktop.Hal", device->udi, "org.freedesktop.Hal.Device.Volume", "Unmount");
if (G_UNLIKELY (message == NULL))
@@ -955,7 +1322,7 @@
{
/* Ups, volume not mounted, we succeed! */
dbus_error_free (&derror);
- return TRUE;
+ goto finish;
}
else
{
@@ -967,7 +1334,11 @@
dbus_error_free (&derror);
return FALSE;
}
-
+finish:
+ if (G_UNLIKELY(backing_udi != NULL))
+ {
+ exo_mount_teardown_crypto_volume(backing_udi);
+ }
return TRUE;
}