Support /etc/crypttab for unlocking and locking LUKS devices
authorDavid Zeuthen <davidz@redhat.com>
Fri, 12 Aug 2011 17:47:57 +0000 (13:47 -0400)
committerDavid Zeuthen <davidz@redhat.com>
Fri, 12 Aug 2011 17:47:57 +0000 (13:47 -0400)
Signed-off-by: David Zeuthen <davidz@redhat.com>
data/org.freedesktop.UDisks2.xml
policy/org.freedesktop.udisks2.policy.in
src/udiskslinuxencrypted.c

index 012791a..005e223 100644 (file)
         small subset per filesystem type is allowed.
 
         If the device in question is referenced in a system-wide
-        configuration file (such as the
-        <citerefentry><refentrytitle>/etc/fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        file)
+        configuration file (such as the <filename>/etc/fstab</filename> file)
         then the
         <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         command is called directly as the calling user.
         option <parameter>force</parameter> is given.
 
         If the device in question is referenced in a system-wide
-        configuration file (such as the
-        <citerefentry><refentrytitle>/etc/fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        file)
+        configuration file (such as the <filename>/etc/fstab</filename> file)
         then the
         <citerefentry><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         command is called directly as the calling user.
 
         Tries to unlock the encrypted device using @passphrase.
 
+        If the device in question is referenced in a system-wide
+        configuration file (such as the <filename>/etc/crypttab</filename> file),
+        then name, options and passphrase (if available) is used from that
+        file after requesting additional authorization.
+
         If the device is removed without being locked (e.g. the user
         yanking the device or pulling the media out) the cleartext
         device will be cleaned up.
index a27b6b2..efa05f3 100644 (file)
     </defaults>
   </action>
 
+  <action id="org.freedesktop.udisks2.encrypted-unlock-crypttab">
+    <_description>Unlock an encrypted device specified in the crypttab file</_description>
+    <_message>Authentication is required to unlock an encrypted device</_message>
+    <defaults>
+      <allow_any>auth_admin</allow_any>
+      <allow_inactive>auth_admin</allow_inactive>
+      <allow_active>auth_admin_keep</allow_active>
+    </defaults>
+  </action>
+
   <action id="org.freedesktop.udisks2.encrypted-lock-others">
     <_description>Lock an encrypted device unlocked by another user</_description>
     <_message>Authentication is required to lock an encrypted device unlocked by another user</_message>
index 1d2fed8..7dba4d3 100644 (file)
@@ -122,6 +122,61 @@ wait_for_cleartext_object (UDisksDaemon *daemon,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static gboolean
+check_crypttab (UDisksBlockDevice   *block,
+                gboolean             load_passphrase,
+                gboolean            *out_found,
+                gchar              **out_name,
+                gchar              **out_passphrase,
+                gchar              **out_options,
+                GError             **error)
+{
+  gboolean ret = FALSE;
+  GVariantIter iter;
+  const gchar *type;
+  GVariant *details;
+
+  g_variant_iter_init (&iter, udisks_block_device_get_configuration (block));
+  while (g_variant_iter_next (&iter, "(&s@a{sv})", &type, &details))
+    {
+      if (g_strcmp0 (type, "crypttab") == 0)
+        {
+          const gchar *passphrase_path;
+          if (out_found != NULL)
+            *out_found = TRUE;
+          g_variant_lookup (details, "name", "^ay", out_name);
+          g_variant_lookup (details, "options", "^ay", out_options);
+          if (g_variant_lookup (details, "passphrase-path", "^&ay", &passphrase_path) &&
+              strlen (passphrase_path) > 0 &&
+              !g_str_has_prefix (passphrase_path, "/dev"))
+            {
+              if (load_passphrase)
+                {
+                  if (!g_file_get_contents (passphrase_path,
+                                            out_passphrase,
+                                            NULL,
+                                            error))
+                    {
+                      g_variant_unref (details);
+                      goto out;
+                    }
+                }
+            }
+          ret = TRUE;
+          g_variant_unref (details);
+          goto out;
+        }
+      g_variant_unref (details);
+    }
+
+  ret = TRUE;
+
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /* runs in thread dedicated to handling @invocation */
 static gboolean
 handle_unlock (UDisksEncrypted        *encrypted,
@@ -142,6 +197,10 @@ handle_unlock (UDisksEncrypted        *encrypted,
   GError *error;
   uid_t caller_uid;
   const gchar *action_id;
+  gboolean is_in_crypttab = FALSE;
+  gchar *crypttab_name = NULL;
+  gchar *crypttab_passphrase = NULL;
+  gchar *crypttab_options = NULL;
 
   object = NULL;
   error_message = NULL;
@@ -201,12 +260,28 @@ handle_unlock (UDisksEncrypted        *encrypted,
       goto out;
     }
 
+  /* check if in crypttab file */
+  error = NULL;
+  if (!check_crypttab (block,
+                       TRUE,
+                       &is_in_crypttab,
+                       &crypttab_name,
+                       &crypttab_passphrase,
+                       &crypttab_options,
+                       &error))
+    {
+      g_dbus_method_invocation_take_error (invocation, error);
+      goto out;
+    }
+
   /* Now, check that the user is actually authorized to unlock the device.
    */
   action_id = "org.freedesktop.udisks2.encrypted-unlock";
   if (udisks_block_device_get_hint_system (block) &&
       !(udisks_daemon_util_setup_by_user (daemon, object, caller_uid)))
     action_id = "org.freedesktop.udisks2.encrypted-unlock-system";
+  if (is_in_crypttab)
+    action_id = "org.freedesktop.udisks2.encrypted-unlock-crypttab";
   if (!udisks_daemon_util_check_authorization_sync (daemon,
                                                     object,
                                                     action_id,
@@ -216,9 +291,18 @@ handle_unlock (UDisksEncrypted        *encrypted,
     goto out;
 
   /* calculate the name to use */
-  name = g_strdup_printf ("LUKS-udisks2-%s", udisks_block_device_get_id_uuid (block));
+  if (is_in_crypttab && crypttab_name != NULL)
+    name = g_strdup (crypttab_name);
+  else
+    name = g_strdup_printf ("LUKS-udisks2-%s", udisks_block_device_get_id_uuid (block));
   escaped_name = g_strescape (name, NULL);
 
+  /* if available, use and prefer the /etc/crypttab passphrase */
+  if (is_in_crypttab && crypttab_passphrase != NULL && strlen (crypttab_passphrase) > 0)
+    {
+      passphrase = crypttab_passphrase;
+    }
+
   /* TODO: support a 'readonly' option */
   if (!udisks_daemon_launch_spawned_job_sync (daemon,
                                               NULL, /* GCancellable */
@@ -280,6 +364,9 @@ handle_unlock (UDisksEncrypted        *encrypted,
                                     g_dbus_object_get_object_path (G_DBUS_OBJECT (cleartext_object)));
 
  out:
+  g_free (crypttab_name);
+  g_free (crypttab_passphrase);
+  g_free (crypttab_options);
   g_free (escaped_name);
   g_free (name);
   g_free (error_message);