[gnome-disk-utility/udisks2-port] Add support for editing /etc/crypttab entries



commit 01b5c4cec092557d174193bfef6824370ed7d43c
Author: David Zeuthen <davidz redhat com>
Date:   Thu Aug 11 15:50:38 2011 -0400

    Add support for editing /etc/crypttab entries
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 data/ui/palimpsest.ui      |  299 ++++++++++++++++++++++
 src/palimpsest/gduwindow.c |  603 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 872 insertions(+), 30 deletions(-)
---
diff --git a/data/ui/palimpsest.ui b/data/ui/palimpsest.ui
index d525b28..efe2ad6 100644
--- a/data/ui/palimpsest.ui
+++ b/data/ui/palimpsest.ui
@@ -287,6 +287,296 @@
       <action-widget response="-5">button2</action-widget>
     </action-widgets>
   </object>
+  <object class="GtkDialog" id="crypttab-dialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="resizable">False</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox7">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area7">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button10">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button9">
+                <property name="label">gtk-apply</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkCheckButton" id="crypttab-configure-checkbutton">
+                <property name="label" translatable="yes">Config_ure passphrase and options</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="has_tooltip">True</property>
+                <property name="tooltip_markup" translatable="yes">Checked if an entry in the /etc/crypttab file exists for the device</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_left">24</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">12</property>
+                <child>
+                  <object class="GtkTable" id="crypttab-table">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="n_rows">5</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">10</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="crypttab-name-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Name</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">crypttab-name-entry</property>
+                        <attributes>
+                          <attribute name="foreground" value="#555555555555"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="crypttab-options-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Options</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">crypttab-options-entry</property>
+                        <attributes>
+                          <attribute name="foreground" value="#555555555555"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="crypttab-name-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="has_tooltip">True</property>
+                        <property name="tooltip_markup" translatable="yes">The name to use for the unlocked device - the device is set up as the name prefixed with &lt;b&gt;/dev/mapper/&lt;/b&gt;</property>
+                        <property name="invisible_char">â</property>
+                        <property name="invisible_char_set">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="crypttab-options-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="has_tooltip">True</property>
+                        <property name="tooltip_markup" translatable="yes">Options to use when unlocking the device</property>
+                        <property name="invisible_char">â</property>
+                        <property name="invisible_char_set">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="crypttab-passphrase-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Passphrase</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">crypttab-passphrase-entry</property>
+                        <attributes>
+                          <attribute name="foreground" value="#555555555555"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="crypttab-passphrase-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="has_tooltip">True</property>
+                        <property name="tooltip_markup" translatable="yes">Passphrase of the device or empty to request from user when setting up the device</property>
+                        <property name="invisible_char">â</property>
+                        <property name="invisible_char_set">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="crypttab-show-passphrase-checkbutton">
+                        <property name="label" translatable="yes">Sho_w passphrase</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="crypttab-passphrase-path-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Passphrase File</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">crypttab-passphrase-entry</property>
+                        <attributes>
+                          <attribute name="foreground" value="#555555555555"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="top_attach">4</property>
+                        <property name="bottom_attach">5</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="crypttab-passphrase-path-value-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="selectable">True</property>
+                        <property name="ellipsize">middle</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">4</property>
+                        <property name="bottom_attach">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLinkButton" id="linkbutton2">
+                    <property name="label" translatable="yes">What's this?</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="has_tooltip">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="relief">none</property>
+                    <property name="xalign">0</property>
+                    <property name="uri">man:crypttab</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">button10</action-widget>
+      <action-widget response="-10">button9</action-widget>
+    </action-widgets>
+  </object>
   <object class="GtkDialog" id="device-fstab-dialog">
     <property name="can_focus">False</property>
     <property name="border_width">5</property>
@@ -672,6 +962,15 @@
       </object>
     </child>
     <child>
+      <object class="GtkMenuItem" id="generic-menu-item-configure-crypttab">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="use_action_appearance">False</property>
+        <property name="label" translatable="yes">Edit /etc/crypttab entry...</property>
+        <property name="use_underline">True</property>
+      </object>
+    </child>
+    <child>
       <object class="GtkMenuItem" id="generic-menu-item-edit-label">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
diff --git a/src/palimpsest/gduwindow.c b/src/palimpsest/gduwindow.c
index f06c31a..6fb8974 100644
--- a/src/palimpsest/gduwindow.c
+++ b/src/palimpsest/gduwindow.c
@@ -88,6 +88,7 @@ struct _GduWindow
 
   GtkWidget *generic_menu;
   GtkWidget *generic_menu_item_configure_fstab;
+  GtkWidget *generic_menu_item_configure_crypttab;
   GtkWidget *generic_menu_item_edit_label;
   GtkWidget *generic_menu_item_edit_partition;
 
@@ -123,6 +124,7 @@ static const struct {
   {G_STRUCT_OFFSET (GduWindow, devtab_toolbar_deactivate_swap_button), "devtab-action-deactivate-swap"},
   {G_STRUCT_OFFSET (GduWindow, generic_menu), "generic-menu"},
   {G_STRUCT_OFFSET (GduWindow, generic_menu_item_configure_fstab), "generic-menu-item-configure-fstab"},
+  {G_STRUCT_OFFSET (GduWindow, generic_menu_item_configure_crypttab), "generic-menu-item-configure-crypttab"},
   {G_STRUCT_OFFSET (GduWindow, generic_menu_item_edit_label), "generic-menu-item-edit-label"},
   {G_STRUCT_OFFSET (GduWindow, generic_menu_item_edit_partition), "generic-menu-item-edit-partition"},
   {0, NULL}
@@ -153,9 +155,10 @@ typedef enum
   SHOW_FLAGS_ENCRYPTED_UNLOCK_BUTTON = (1<<7),
   SHOW_FLAGS_ENCRYPTED_LOCK_BUTTON   = (1<<8),
 
-  SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB = (1<<9),
-  SHOW_FLAGS_POPUP_MENU_EDIT_LABEL = (1<<10),
-  SHOW_FLAGS_POPUP_MENU_EDIT_PARTITION = (1<<11),
+  SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB    = (1<<9),
+  SHOW_FLAGS_POPUP_MENU_CONFIGURE_CRYPTTAB = (1<<10),
+  SHOW_FLAGS_POPUP_MENU_EDIT_LABEL         = (1<<11),
+  SHOW_FLAGS_POPUP_MENU_EDIT_PARTITION     = (1<<12),
 } ShowFlags;
 
 static void gdu_window_show_error (GduWindow   *window,
@@ -181,6 +184,8 @@ static void on_devtab_action_deactivate_swap_activated (GtkAction *action, gpoin
 
 static void on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
                                                   gpointer   user_data);
+static void on_generic_menu_item_configure_crypttab (GtkMenuItem *menu_item,
+                                                     gpointer   user_data);
 static void on_generic_menu_item_edit_label (GtkMenuItem *menu_item,
                                              gpointer   user_data);
 static void on_generic_menu_item_edit_partition (GtkMenuItem *menu_item,
@@ -323,6 +328,8 @@ update_for_show_flags (GduWindow *window,
 
   gtk_widget_set_visible (GTK_WIDGET (window->generic_menu_item_configure_fstab),
                           show_flags & SHOW_FLAGS_POPUP_MENU_CONFIGURE_FSTAB);
+  gtk_widget_set_visible (GTK_WIDGET (window->generic_menu_item_configure_crypttab),
+                          show_flags & SHOW_FLAGS_POPUP_MENU_CONFIGURE_CRYPTTAB);
   gtk_widget_set_visible (GTK_WIDGET (window->generic_menu_item_edit_label),
                           show_flags & SHOW_FLAGS_POPUP_MENU_EDIT_LABEL);
   gtk_widget_set_visible (GTK_WIDGET (window->generic_menu_item_edit_partition),
@@ -839,6 +846,10 @@ gdu_window_constructed (GObject *object)
                     "activate",
                     G_CALLBACK (on_generic_menu_item_configure_fstab),
                     window);
+  g_signal_connect (window->generic_menu_item_configure_crypttab,
+                    "activate",
+                    G_CALLBACK (on_generic_menu_item_configure_crypttab),
+                    window);
   g_signal_connect (window->generic_menu_item_edit_label,
                     "activate",
                     G_CALLBACK (on_generic_menu_item_edit_label),
@@ -1671,37 +1682,64 @@ update_device_page_for_block (GduWindow          *window,
                   "devtab-volume-encrypted-unlocked-value-label",
                   str,
                   SET_MARKUP_FLAGS_NONE);
+
+      *show_flags |= SHOW_FLAGS_POPUP_MENU_CONFIGURE_CRYPTTAB;
     }
 
   /* Configuration */
   if (TRUE)
     {
-      const gchar *s;
+      GString *str;
       GVariantIter iter;
       const gchar *config_type;
-      gboolean in_fstab = FALSE;
+      gboolean mentioned_fstab = FALSE;
+      gboolean mentioned_crypttab = FALSE;
+
+      str = g_string_new (NULL);
 
       g_variant_iter_init (&iter, udisks_block_device_get_configuration (block));
       while (g_variant_iter_next (&iter, "(&sa{sv})", &config_type, NULL))
         {
           if (g_strcmp0 (config_type, "fstab") == 0)
-            in_fstab = TRUE;
-        }
-
-      s = NULL;
-      if (in_fstab)
-        {
-          /* Translators: Shown when the device is configured in /etc/fstab.
-           * Do not translate "fstab".
-           */
-          s = _("In /etc/fstab");
+            {
+              if (!mentioned_fstab)
+                {
+                  mentioned_fstab = TRUE;
+                  if (str->len > 0)
+                    g_string_append (str, ", ");
+                  /* Translators: Shown when the device is configured in /etc/fstab.
+                   * Do not translate "/etc/fstab".
+                   */
+                  g_string_append (str, _("In /etc/fstab"));
+                }
+            }
+          else if (g_strcmp0 (config_type, "crypttab") == 0)
+            {
+              if (!mentioned_crypttab)
+                {
+                  mentioned_crypttab = TRUE;
+                  if (str->len > 0)
+                    g_string_append (str, ", ");
+                  /* Translators: Shown when the device is configured in /etc/crypttab.
+                   * Do not translate "/etc/crypttab".
+                   */
+                  g_string_append (str, _("In /etc/crypttab"));
+                }
+            }
+          else
+            {
+              if (str->len > 0)
+                g_string_append (str, ", ");
+              g_string_append (str, config_type);
+            }
         }
 
       set_markup (window,
                   "devtab-volume-configured-label",
                   "devtab-volume-configured-value-label",
-                  s,
+                  str->str,
                   SET_MARKUP_FLAGS_HYPHEN_IF_EMPTY);
+      g_string_free (str, TRUE);
     }
 
 }
@@ -2578,6 +2616,8 @@ on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
       gint ui_freq;
       gint ui_passno;
       GError *error;
+      GVariant *old_item;
+      GVariant *new_item;
 
       ui_configured = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data.configure_checkbutton));
       ui_fsname = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (data.device_combobox));
@@ -2589,12 +2629,32 @@ on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
 
       gtk_widget_hide (dialog);
 
+      old_item = NULL;
+      new_item = NULL;
+
       if (configured)
         {
+          old_item = g_variant_new ("(s a{sv})", "fstab", data.orig_fstab_entry);
+        }
+
+      if (ui_configured)
+        {
+          GVariantBuilder builder;
+          g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+          g_variant_builder_add (&builder, "{sv}", "fsname", g_variant_new_bytestring (ui_fsname));
+          g_variant_builder_add (&builder, "{sv}", "dir", g_variant_new_bytestring (ui_dir));
+          g_variant_builder_add (&builder, "{sv}", "type", g_variant_new_bytestring (ui_type));
+          g_variant_builder_add (&builder, "{sv}", "opts", g_variant_new_bytestring (ui_opts));
+          g_variant_builder_add (&builder, "{sv}", "freq", g_variant_new_int32 (ui_freq));
+          g_variant_builder_add (&builder, "{sv}", "passno", g_variant_new_int32 (ui_passno));
+          new_item = g_variant_new ("(sa{sv})", "fstab", &builder);
+        }
+
+      if (old_item != NULL && new_item == NULL)
+        {
           error = NULL;
           if (!udisks_block_device_call_remove_configuration_item_sync (block,
-                                                                        g_variant_new ("(s a{sv})", "fstab",
-                                                                                       data.orig_fstab_entry),
+                                                                        old_item,
                                                                         g_variant_new ("a{sv}", NULL), /* options */
                                                                         NULL, /* GCancellable */
                                                                         &error))
@@ -2607,20 +2667,11 @@ on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
               goto out;
             }
         }
-
-      if (ui_configured)
+      else if (old_item == NULL && new_item != NULL)
         {
-          GVariantBuilder builder;
-          g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
-          g_variant_builder_add (&builder, "{sv}", "fsname", g_variant_new_bytestring (ui_fsname));
-          g_variant_builder_add (&builder, "{sv}", "dir", g_variant_new_bytestring (ui_dir));
-          g_variant_builder_add (&builder, "{sv}", "type", g_variant_new_bytestring (ui_type));
-          g_variant_builder_add (&builder, "{sv}", "opts", g_variant_new_bytestring (ui_opts));
-          g_variant_builder_add (&builder, "{sv}", "freq", g_variant_new_int32 (ui_freq));
-          g_variant_builder_add (&builder, "{sv}", "passno", g_variant_new_int32 (ui_passno));
           error = NULL;
           if (!udisks_block_device_call_add_configuration_item_sync (block,
-                                                                     g_variant_new ("(sa{sv})", "fstab", &builder),
+                                                                     new_item,
                                                                      g_variant_new ("a{sv}", NULL), /* options */
                                                                      NULL, /* GCancellable */
                                                                      &error))
@@ -2633,7 +2684,28 @@ on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
               goto out;
             }
         }
-
+      else if (old_item != NULL && new_item != NULL)
+        {
+          error = NULL;
+          if (!udisks_block_device_call_update_configuration_item_sync (block,
+                                                                        old_item,
+                                                                        new_item,
+                                                                        g_variant_new ("a{sv}", NULL), /* options */
+                                                                        NULL, /* GCancellable */
+                                                                        &error))
+            {
+              gdu_window_show_error (window,
+                                     _("Error updating /etc/fstab entry"),
+                                     error);
+              g_error_free (error);
+              g_free (ui_fsname);
+              goto out;
+            }
+        }
+      else
+        {
+          g_assert_not_reached ();
+        }
       g_free (ui_fsname);
     }
 
@@ -2649,6 +2721,477 @@ on_generic_menu_item_configure_fstab (GtkMenuItem *menu_item,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct
+{
+  UDisksBlockDevice *block;
+
+  GduWindow *window;
+
+  GtkBuilder *builder;
+  GtkWidget *dialog;
+  GtkWidget *configure_checkbutton;
+  GtkWidget *table;
+
+  GtkWidget *name_entry;
+  GtkWidget *options_entry;
+  GtkWidget *passphrase_label;
+  GtkWidget *passphrase_entry;
+  GtkWidget *show_passphrase_checkbutton;
+  GtkWidget *passphrase_path_value_label;
+
+  GVariant *orig_crypttab_entry;
+} CrypttabDialogData;
+
+static void
+crypttab_dialog_free (CrypttabDialogData *data)
+{
+  g_object_unref (data->window);
+
+  if (data->orig_crypttab_entry != NULL)
+    g_variant_unref (data->orig_crypttab_entry);
+
+  if (data->dialog != NULL)
+    {
+      gtk_widget_hide (data->dialog);
+      gtk_widget_destroy (data->dialog);
+    }
+  g_object_unref (data->builder);
+  g_free (data);
+}
+
+static void
+crypttab_dialog_update (CrypttabDialogData *data)
+{
+  gboolean ui_configured;
+  const gchar *ui_name;
+  const gchar *ui_options;
+  const gchar *ui_passphrase_contents;
+  gboolean configured;
+  const gchar *name;
+  const gchar *passphrase_path;
+  const gchar *passphrase_contents;
+  const gchar *options;
+  gboolean can_apply;
+  gchar *s;
+
+  if (data->orig_crypttab_entry != NULL)
+    {
+      configured = TRUE;
+      g_variant_lookup (data->orig_crypttab_entry, "name", "^&ay", &name);
+      g_variant_lookup (data->orig_crypttab_entry, "options", "^&ay", &options);
+      g_variant_lookup (data->orig_crypttab_entry, "passphrase-path", "^&ay", &passphrase_path);
+      if (!g_variant_lookup (data->orig_crypttab_entry, "passphrase-contents", "^&ay", &passphrase_contents))
+        passphrase_contents = "";
+    }
+  else
+    {
+      configured = FALSE;
+      name = "";
+      options = "";
+      passphrase_path = "";
+      passphrase_contents = "";
+    }
+
+  ui_configured = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->configure_checkbutton));
+  ui_name = gtk_entry_get_text (GTK_ENTRY (data->name_entry));
+  ui_options = gtk_entry_get_text (GTK_ENTRY (data->options_entry));
+  ui_passphrase_contents = gtk_entry_get_text (GTK_ENTRY (data->passphrase_entry));
+
+  if (!configured)
+    {
+      if (strlen (ui_passphrase_contents) > 0)
+        s = g_strdup_printf ("<i>%s</i>", _("Will be created"));
+      else
+        s = g_strdup_printf ("<i>%s</i>", _("None"));
+    }
+  else
+    {
+      if (g_str_has_prefix (passphrase_path, "/dev"))
+        {
+          /* if using a random source (for e.g. setting up swap), don't offer to edit the passphrase */
+          gtk_widget_hide (data->passphrase_label);
+          gtk_widget_hide (data->passphrase_entry);
+          gtk_widget_hide (data->show_passphrase_checkbutton);
+          gtk_widget_set_no_show_all (data->passphrase_label, TRUE);
+          gtk_widget_set_no_show_all (data->passphrase_entry, TRUE);
+          gtk_widget_set_no_show_all (data->show_passphrase_checkbutton, TRUE);
+          s = g_strdup (passphrase_path);
+        }
+      else if (strlen (ui_passphrase_contents) > 0)
+        {
+          if (strlen (passphrase_path) == 0)
+            s = g_strdup_printf ("<i>%s</i>", _("Will be created"));
+          else
+            s = g_strdup (passphrase_path);
+        }
+      else
+        {
+          if (strlen (passphrase_path) == 0)
+            s = g_strdup_printf ("<i>%s</i>", _("None"));
+          else
+            s = g_strdup_printf ("<i>%s</i>", _("Will be deleted"));
+        }
+    }
+  gtk_label_set_markup (GTK_LABEL (data->passphrase_path_value_label), s);
+  g_free (s);
+
+  can_apply = FALSE;
+  if (configured != ui_configured)
+    {
+      can_apply = TRUE;
+    }
+  else if (ui_configured)
+    {
+      if (g_strcmp0 (ui_name, name) != 0 ||
+          g_strcmp0 (ui_options, options) != 0 ||
+          g_strcmp0 (ui_passphrase_contents, passphrase_contents) != 0)
+        {
+          can_apply = TRUE;
+        }
+    }
+
+  gtk_dialog_set_response_sensitive (GTK_DIALOG (data->dialog),
+                                     GTK_RESPONSE_APPLY,
+                                     can_apply);
+}
+
+static void
+crypttab_dialog_property_changed (GObject     *object,
+                                  GParamSpec  *pspec,
+                                  gpointer     user_data)
+{
+  CrypttabDialogData *data = user_data;
+  crypttab_dialog_update (data);
+}
+
+
+static void
+crypttab_dialog_present (CrypttabDialogData *data)
+{
+  gboolean configured;
+  gchar *name;
+  const gchar *options;
+  const gchar *passphrase_contents;
+  gint response;
+
+  if (data->orig_crypttab_entry != NULL)
+    {
+      configured = TRUE;
+      g_variant_lookup (data->orig_crypttab_entry, "name", "^ay", &name);
+      g_variant_lookup (data->orig_crypttab_entry, "options", "^&ay", &options);
+      if (!g_variant_lookup (data->orig_crypttab_entry, "passphrase-contents", "^&ay", &passphrase_contents))
+        passphrase_contents = "";
+    }
+  else
+    {
+      configured = FALSE;
+      name = g_strdup_printf ("luks-%s", udisks_block_device_get_id_uuid (data->block));
+      options = "";
+      passphrase_contents = "";
+    }
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->configure_checkbutton), configured);
+  gtk_entry_set_text (GTK_ENTRY (data->name_entry), name);
+  gtk_entry_set_text (GTK_ENTRY (data->options_entry), options);
+  gtk_entry_set_text (GTK_ENTRY (data->passphrase_entry), passphrase_contents);
+
+  g_object_bind_property (data->show_passphrase_checkbutton,
+                          "active",
+                          data->passphrase_entry,
+                          "visibility",
+                          G_BINDING_SYNC_CREATE);
+
+  g_object_bind_property (data->configure_checkbutton,
+                          "active",
+                          data->table,
+                          "sensitive",
+                          G_BINDING_SYNC_CREATE);
+
+  g_signal_connect (data->configure_checkbutton,
+                    "notify::active", G_CALLBACK (crypttab_dialog_property_changed), data);
+  g_signal_connect (data->name_entry,
+                    "notify::text", G_CALLBACK (crypttab_dialog_property_changed), data);
+  g_signal_connect (data->options_entry,
+                    "notify::text", G_CALLBACK (crypttab_dialog_property_changed), data);
+  g_signal_connect (data->passphrase_entry,
+                    "notify::text", G_CALLBACK (crypttab_dialog_property_changed), data);
+
+  gtk_widget_show_all (data->dialog);
+
+  crypttab_dialog_update (data);
+
+  response = gtk_dialog_run (GTK_DIALOG (data->dialog));
+
+  if (response == GTK_RESPONSE_APPLY)
+    {
+      gboolean ui_configured;
+      const gchar *ui_name;
+      const gchar *ui_options;
+      const gchar *ui_passphrase_contents;
+      const gchar *old_passphrase_path;
+      GError *error;
+      GVariant *old_item;
+      GVariant *new_item;
+
+      ui_configured = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->configure_checkbutton));
+      ui_name = gtk_entry_get_text (GTK_ENTRY (data->name_entry));
+      ui_options = gtk_entry_get_text (GTK_ENTRY (data->options_entry));
+      ui_passphrase_contents = gtk_entry_get_text (GTK_ENTRY (data->passphrase_entry));
+
+      gtk_widget_hide (data->dialog);
+
+      old_item = NULL;
+      new_item = NULL;
+
+      old_passphrase_path = NULL;
+      if (data->orig_crypttab_entry != NULL)
+        {
+          const gchar *s;
+          if (g_variant_lookup (data->orig_crypttab_entry, "passphrase-path", "^&ay", &s))
+            {
+              if (strlen (s) > 0 && !g_str_has_prefix (s, "/dev"))
+                old_passphrase_path = s;
+            }
+          error = NULL;
+          old_item = g_variant_new ("(s a{sv})", "crypttab",
+                                    data->orig_crypttab_entry);
+        }
+
+      if (ui_configured)
+        {
+          GVariantBuilder builder;
+          gchar *s;
+          g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+          s = g_strdup_printf ("UUID=%s", udisks_block_device_get_id_uuid (data->block));
+          g_variant_builder_add (&builder, "{sv}", "device", g_variant_new_bytestring (s));
+          g_free (s);
+          g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_bytestring (ui_name));
+          g_variant_builder_add (&builder, "{sv}", "options", g_variant_new_bytestring (ui_options));
+          if (strlen (ui_passphrase_contents) > 0)
+            {
+              /* use old/existing passphrase file, if available */
+              if (old_passphrase_path != NULL)
+                {
+                  g_variant_builder_add (&builder, "{sv}", "passphrase-path",
+                                         g_variant_new_bytestring (old_passphrase_path));
+                }
+              else
+                {
+                  /* otherwise fall back to the requested name */
+                  s = g_strdup_printf ("/etc/luks-keys/%s", ui_name);
+                  g_variant_builder_add (&builder, "{sv}", "passphrase-path", g_variant_new_bytestring (s));
+                  g_free (s);
+                }
+              g_variant_builder_add (&builder, "{sv}", "passphrase-contents",
+                                     g_variant_new_bytestring (ui_passphrase_contents));
+
+            }
+          else
+            {
+              g_variant_builder_add (&builder, "{sv}", "passphrase-path",
+                                     g_variant_new_bytestring (""));
+              g_variant_builder_add (&builder, "{sv}", "passphrase-contents",
+                                     g_variant_new_bytestring (""));
+            }
+
+          new_item = g_variant_new ("(sa{sv})", "crypttab", &builder);
+        }
+
+      if (old_item != NULL && new_item == NULL)
+        {
+          error = NULL;
+          if (!udisks_block_device_call_remove_configuration_item_sync (data->block,
+                                                                        old_item,
+                                                                        g_variant_new ("a{sv}", NULL), /* options */
+                                                                        NULL, /* GCancellable */
+                                                                        &error))
+            {
+              gdu_window_show_error (data->window,
+                                     _("Error removing /etc/crypttab entry"),
+                                     error);
+              g_error_free (error);
+              goto out;
+            }
+        }
+      else if (old_item == NULL && new_item != NULL)
+        {
+          error = NULL;
+          if (!udisks_block_device_call_add_configuration_item_sync (data->block,
+                                                                     new_item,
+                                                                     g_variant_new ("a{sv}", NULL), /* options */
+                                                                     NULL, /* GCancellable */
+                                                                     &error))
+            {
+              gdu_window_show_error (data->window,
+                                     _("Error adding /etc/crypttab entry"),
+                                     error);
+              g_error_free (error);
+              goto out;
+            }
+        }
+      else if (old_item != NULL && new_item != NULL)
+        {
+          error = NULL;
+          if (!udisks_block_device_call_update_configuration_item_sync (data->block,
+                                                                        old_item,
+                                                                        new_item,
+                                                                        g_variant_new ("a{sv}", NULL), /* options */
+                                                                        NULL, /* GCancellable */
+                                                                        &error))
+            {
+              gdu_window_show_error (data->window,
+                                     _("Error updating /etc/crypttab entry"),
+                                     error);
+              g_error_free (error);
+              goto out;
+            }
+        }
+      else
+        {
+          g_assert_not_reached ();
+        }
+    }
+
+ out:
+  crypttab_dialog_free (data);
+  g_free (name);
+}
+
+static void
+crypttab_dialog_on_get_secrets_cb (UDisksBlockDevice *block,
+                                   GAsyncResult      *res,
+                                   gpointer           user_data)
+{
+  CrypttabDialogData *data = user_data;
+  GError *error;
+  GVariant *configuration;
+  GVariantIter iter;
+  const gchar *configuration_type;
+  GVariant *configuration_dict;
+
+  configuration = NULL;
+  error = NULL;
+  if (!udisks_block_device_call_get_secret_configuration_finish (block,
+                                                                 &configuration,
+                                                                 res,
+                                                                 &error))
+    {
+      gdu_window_show_error (data->window,
+                             _("Error retrieving configuration data"),
+                             error);
+      g_error_free (error);
+      crypttab_dialog_free (data);
+      goto out;
+    }
+
+  /* there could be multiple crypttab entries - we only consider the first one */
+  g_variant_iter_init (&iter, configuration);
+  while (g_variant_iter_next (&iter, "(&s a{sv})", &configuration_type, &configuration_dict))
+    {
+      if (g_strcmp0 (configuration_type, "crypttab") == 0)
+        {
+          if (data->orig_crypttab_entry != NULL)
+            g_variant_unref (data->orig_crypttab_entry);
+          data->orig_crypttab_entry = configuration_dict;
+          break;
+        }
+      else
+        {
+          g_variant_unref (configuration_dict);
+        }
+    }
+  g_variant_unref (configuration);
+
+  crypttab_dialog_present (data);
+
+ out:
+  ;
+}
+
+static void
+on_generic_menu_item_configure_crypttab (GtkMenuItem *menu_item,
+                                         gpointer   user_data)
+{
+  GduWindow *window = GDU_WINDOW (user_data);
+  UDisksObject *object;
+  GtkWidget *dialog;
+  CrypttabDialogData *data;
+  GVariantIter iter;
+  const gchar *configuration_type;
+  GVariant *configuration_dict;
+  gboolean configured;
+  gboolean get_passphrase_contents;
+
+  data = g_new0 (CrypttabDialogData, 1);
+  data->window = g_object_ref (window);
+
+  object = gdu_volume_grid_get_selected_device (GDU_VOLUME_GRID (window->volume_grid));
+  if (object == NULL)
+    object = gdu_volume_grid_get_block_device (GDU_VOLUME_GRID (window->volume_grid));
+  data->block = udisks_object_peek_block_device (object);
+  g_assert (data->block != NULL);
+
+  dialog = gdu_window_new_widget (window, "crypttab-dialog", &data->builder);
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+  data->dialog = dialog;
+  data->configure_checkbutton = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-configure-checkbutton"));
+  data->table = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-table"));
+  data->name_entry = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-name-entry"));
+  data->options_entry = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-options-entry"));
+  data->passphrase_label = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-passphrase-label"));
+  data->passphrase_entry = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-passphrase-entry"));
+  data->show_passphrase_checkbutton = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-show-passphrase-checkbutton"));
+  data->passphrase_path_value_label = GTK_WIDGET (gtk_builder_get_object (data->builder, "crypttab-passphrase-path-value-label"));
+
+  /* First check if there's an existing configuration */
+  configured = FALSE;
+  get_passphrase_contents = FALSE;
+  g_variant_iter_init (&iter, udisks_block_device_get_configuration (data->block));
+  while (g_variant_iter_next (&iter, "(&s a{sv})", &configuration_type, &configuration_dict))
+    {
+      if (g_strcmp0 (configuration_type, "crypttab") == 0)
+        {
+          const gchar *passphrase_path;
+          configured = TRUE;
+          g_variant_lookup (configuration_dict, "passphrase-path", "^&ay", &passphrase_path);
+          if (g_strcmp0 (passphrase_path, "") != 0)
+            {
+              /* fetch contents of passphrase file, if it exists (unless special file) */
+              if (!g_str_has_prefix (passphrase_path, "/dev"))
+                {
+                  get_passphrase_contents = TRUE;
+                }
+            }
+          data->orig_crypttab_entry = configuration_dict;
+          break;
+        }
+      else
+        {
+          g_variant_unref (configuration_dict);
+        }
+    }
+
+  /* if there is an existing configuration and it has a passphrase, get the actual passphrase
+   * as well (involves polkit dialog)
+   */
+  if (configured && get_passphrase_contents)
+    {
+      udisks_block_device_call_get_secret_configuration (data->block,
+                                                         g_variant_new ("a{sv}", NULL), /* options */
+                                                         NULL, /* cancellable */
+                                                         (GAsyncReadyCallback) crypttab_dialog_on_get_secrets_cb,
+                                                         data);
+    }
+  else
+    {
+      /* otherwise just set up the dialog */
+      crypttab_dialog_present (data);
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 mount_cb (UDisksFilesystem *filesystem,
           GAsyncResult     *res,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]