Add support for /etc/crypttab
authorDavid Zeuthen <davidz@redhat.com>
Thu, 11 Aug 2011 19:46:12 +0000 (15:46 -0400)
committerDavid Zeuthen <davidz@redhat.com>
Thu, 11 Aug 2011 19:46:12 +0000 (15:46 -0400)
Signed-off-by: David Zeuthen <davidz@redhat.com>
16 files changed:
data/org.freedesktop.UDisks2.xml
doc/udisks2-docs.xml
doc/udisks2-sections.txt
doc/udisks2.types
policy/org.freedesktop.udisks2.policy.in
src/Makefile.am
src/udiskscrypttabentry.c [new file with mode: 0644]
src/udiskscrypttabentry.h [new file with mode: 0644]
src/udiskscrypttabmonitor.c [new file with mode: 0644]
src/udiskscrypttabmonitor.h [new file with mode: 0644]
src/udisksdaemon.c
src/udisksdaemon.h
src/udisksdaemontypes.h
src/udiskslinuxblock.c
src/udiskslinuxprovider.c
src/udisksprivate.h

index 7048cee..4a5b21c 100644 (file)
     <property name="IdUUID" type="ay" access="read"/>
 
     <!-- Configuration:
-         The configuration sources for the device.
+         The configuration for the device.
 
          This is an array of pairs of (@type, @details) where @type is
          a string identifying the configuration source
          (e.g. <literal>fstab</literal>) and @details contains the
          actual configuration data.
 
+         Use the
+         org.freedesktop.UDisks2.BlockDevice.AddConfigurationItem(),
+         org.freedesktop.UDisks2.BlockDevice.RemoveConfigurationItem()
+         and
+         org.freedesktop.UDisks2.BlockDevice.UpdateConfigurationItem()
+         methods to add, remove and update configuration items.
+
+         Use
+         org.freedesktop.UDisks2.BlockDevice.GetSecretConfiguration()
+         to get the secrets (e.g. passphrases) that may be part of the
+         configuration but isn't exported in this property for
+         security reasons.
+
          For entries of type <literal>fstab</literal>, it means that
          the block device is referenced in the system-wide
          <filename>/etc/fstab</filename> file. Known configuration
          </varlistentry>
          </variablelist>
 
-         Use the
+         For entries of type <literal>crypttab</literal>, it means that
+         the block device is referenced in the system-wide
+         <filename>/etc/crypttab</filename> file. Known configuration
+         items for type <literal>crypttab</literal> are
+         <variablelist>
+         <varlistentry>
+           <term>name (type <literal>'ay'</literal>)</term>
+           <listitem><para>The name to set the device up as</para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>device (type <literal>'ay'</literal>)</term>
+           <listitem><para>The special device</para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>passphrase-path (type <literal>'ay'</literal>)</term>
+           <listitem><para>Either empty to specify that no password is set,
+           otherwise a path to a file containing the encryption password.
+           This may also point to a special device file in <filename>/dev</filename>
+           such as <literal>/dev/random</literal>.
+           </para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>passphrase-contents (type <literal>'ay'</literal>)</term>
+           <listitem><para>The contents of the file containing the encryption password, if applicable.
+           This is only available via the org.freedesktop.UDisks2.BlockDevice.GetSecretConfiguration()
+           method.</para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>opts (type <literal>'ay'</literal>)</term>
+           <listitem><para>Options</para></listitem>
+         </varlistentry>
+         </variablelist>
+         For security reasons, when creating a new
+         <literal>crypttab</literal> entry (via the
          org.freedesktop.UDisks2.BlockDevice.AddConfigurationItem()
-         and
-         org.freedesktop.UDisks2.BlockDevice.RemoveConfigurationItem()
-         methods to add/remove configuration items.
+         method), then the <option>passphrase-path</option> must
+         reference an unexisting file in the
+         <filename>/etc/luks-keys</filename> directory.
     -->
     <property name="Configuration" type="a(sa{sv})" access="read"/>
 
         @item: The configuration item to add.
         @options: Options (currently unused except for <link linkend="udisks-std-options">standard options</link>).
 
-        Adds a new configuration item. See the
-        #org.freedesktop.UDisks2.BlockDevice:Configuration property
-        for details about valid configuration items.
+        Adds a new configuration item.
+
+        See the #org.freedesktop.UDisks2.BlockDevice:Configuration
+        property for details about valid configuration items.
     -->
     <method name="AddConfigurationItem">
       <arg name="item" direction="in" type="(sa{sv})"/>
         @item: The configuration item to remove.
         @options: Options (currently unused except for <link linkend="udisks-std-options">standard options</link>).
 
-        Removes a new configuration item. See the
-        #org.freedesktop.UDisks2.BlockDevice:Configuration property
-        for details about valid configuration items.
+        Removes an existing configuration item.
+
+        See the #org.freedesktop.UDisks2.BlockDevice:Configuration
+        property for details about valid configuration items.
     -->
     <method name="RemoveConfigurationItem">
       <arg name="item" direction="in" type="(sa{sv})"/>
       <arg name="options" direction="in" type="a{sv}"/>
     </method>
 
+    <!--
+        UpdateConfigurationItem:
+        @old_item: The configuration item to remove.
+        @new_item: The configuration item to add. Must be of the same type as @old_item.
+        @options: Options (currently unused except for <link linkend="udisks-std-options">standard options</link>).
+
+        Removes a configuration item and adds a new one. This is
+        equivalent to calling
+        org.freedesktop.UDisks2.BlockDevice.RemoveConfigurationItem()
+        followed by
+        org.freedesktop.UDisks2.BlockDevice.AddConfigurationItem()
+        with the change that only one PolicyKit check is made
+        and that @new_item can be validated against @old_item.
+
+        See the #org.freedesktop.UDisks2.BlockDevice:Configuration
+        property for details about valid configuration items.
+    -->
+    <method name="UpdateConfigurationItem">
+      <arg name="old_item" direction="in" type="(sa{sv})"/>
+      <arg name="new_item" direction="in" type="(sa{sv})"/>
+      <arg name="options" direction="in" type="a{sv}"/>
+    </method>
+
+    <!--
+        GetSecretConfiguration:
+        @options: Options (currently unused except for <link linkend="udisks-std-options">standard options</link>).
+        @configuration: The resulting configuration.
+
+        Returns the same value as in the
+        #org.freedesktop.UDisks2.BlockDevice:Configuration property
+        but without secret information filtered out.
+    -->
+    <method name="GetSecretConfiguration">
+      <arg name="options" direction="in" type="a{sv}"/>
+      <arg name="configuration" direction="out" type="a(sa{sv})"/>
+    </method>
+
   </interface>
 
   <!-- ********************************************************************** -->
index 8cd93c6..854f37e 100644 (file)
     <xi:include href="xml/udisksmountmonitor.xml"/>
     <xi:include href="xml/udisksfstabentry.xml"/>
     <xi:include href="xml/udisksfstabmonitor.xml"/>
+    <xi:include href="xml/udiskscrypttabentry.xml"/>
+    <xi:include href="xml/udiskscrypttabmonitor.xml"/>
     <xi:include href="xml/udiskspersistentstore.xml"/>
     <xi:include href="xml/udiskscleanup.xml"/>
     <xi:include href="xml/udisksprovider.xml"/>
index b29bcc1..b6ca719 100644 (file)
@@ -59,6 +59,7 @@ udisks_daemon_get_connection
 udisks_daemon_get_object_manager
 udisks_daemon_get_mount_monitor
 udisks_daemon_get_fstab_monitor
+udisks_daemon_get_crypttab_monitor
 udisks_daemon_get_linux_provider
 udisks_daemon_get_persistent_store
 udisks_daemon_get_authority
@@ -1018,3 +1019,34 @@ UDISKS_IS_FSTAB_MONITOR
 <SUBSECTION Private>
 udisks_fstab_monitor_get_type
 </SECTION>
+
+<SECTION>
+<FILE>udiskscrypttabentry</FILE>
+<TITLE>UDisksCrypttabEntry</TITLE>
+UDisksCrypttabEntry
+udisks_crypttab_entry_get_name
+udisks_crypttab_entry_get_device
+udisks_crypttab_entry_get_passphrase_path
+udisks_crypttab_entry_get_options
+udisks_crypttab_entry_compare
+<SUBSECTION Standard>
+UDISKS_TYPE_CRYPTTAB_ENTRY
+UDISKS_CRYPTTAB_ENTRY
+UDISKS_IS_CRYPTTAB_ENTRY
+<SUBSECTION Private>
+udisks_crypttab_entry_get_type
+</SECTION>
+
+<SECTION>
+<FILE>udiskscrypttabmonitor</FILE>
+<TITLE>UDisksCrypttabMonitor</TITLE>
+UDisksCrypttabMonitor
+udisks_crypttab_monitor_new
+udisks_crypttab_monitor_get_entries
+<SUBSECTION Standard>
+UDISKS_TYPE_CRYPTTAB_MONITOR
+UDISKS_CRYPTTAB_MONITOR
+UDISKS_IS_CRYPTTAB_MONITOR
+<SUBSECTION Private>
+udisks_crypttab_monitor_get_type
+</SECTION>
index 79031a2..7b0ceee 100644 (file)
@@ -20,6 +20,8 @@ udisks_linux_manager_get_type
 udisks_cleanup_get_type
 udisks_fstab_entry_get_type
 udisks_fstab_monitor_get_type
+udisks_crypttab_entry_get_type
+udisks_crypttab_monitor_get_type
 
 udisks_drive_get_type
 udisks_drive_proxy_get_type
index 9d76a85..8e61608 100644 (file)
     </defaults>
   </action>
 
-  <!-- Manage system-wide configuration files such as /etc/fstab -->
+  <!-- Manage system-wide configuration files such as /etc/fstab or
+       /etc/crypttab ... including files referenced by these files.
+
+       It is insecure to automatically grant this to groups of users or
+       to allow a process to retain the authorization.
+  -->
   <action id="org.freedesktop.udisks2.modify-system-configuration">
     <_description>Modify system-wide configuration</_description>
     <_message>Authentication is required to modify system-wide configuration</_message>
     <defaults>
       <allow_any>auth_admin</allow_any>
       <allow_inactive>auth_admin</allow_inactive>
-      <allow_active>auth_admin_keep</allow_active>
+      <allow_active>auth_admin</allow_active>
+    </defaults>
+  </action>
+
+  <!-- Get secrets from system-wide configuration files -->
+  <action id="org.freedesktop.udisks2.read-system-configuration-secrets">
+    <_description>Modify system-wide configuration</_description>
+    <_message>Authentication is required to retrieve secrets from system-wide configuration</_message>
+    <defaults>
+      <allow_any>auth_admin</allow_any>
+      <allow_inactive>auth_admin</allow_inactive>
+      <allow_active>auth_admin</allow_active>
     </defaults>
   </action>
 
index b23e7de..962cf12 100644 (file)
@@ -67,6 +67,8 @@ libudisks_daemon_la_SOURCES =                                         \
        udisksprivate.h                                                 \
        udisksfstabentry.h              udisksfstabentry.c              \
        udisksfstabmonitor.h            udisksfstabmonitor.c            \
+       udiskscrypttabentry.h           udiskscrypttabentry.c           \
+       udiskscrypttabmonitor.h         udiskscrypttabmonitor.c         \
        $(BUILT_SOURCES)                                                \
        $(NULL)
 
diff --git a/src/udiskscrypttabentry.c b/src/udiskscrypttabentry.c
new file mode 100644 (file)
index 0000000..71181cc
--- /dev/null
@@ -0,0 +1,214 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <zeuthen@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <mntent.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "udiskscrypttabentry.h"
+#include "udisksprivate.h"
+
+/**
+ * SECTION:udiskscrypttabentry
+ * @title: UDisksCrypttabEntry
+ * @short_description: Object corresponding to an entry in the crypttab file
+ *
+ * Object corresponding to an entry in the
+ * <filename>/etc/crypttab</filename> file. You cannot instantiate this
+ * type yourself – use #UDisksCrypttabMonitor.
+ */
+
+/**
+ * UDisksCrypttabEntry:
+ *
+ * The #UDisksCrypttabEntry structure contains only private data and should
+ * only be accessed using the provided API.
+ */
+struct _UDisksCrypttabEntry
+{
+  GObject parent_instance;
+
+  gchar *name;
+  gchar *device;
+  gchar *passphrase_path;
+  gchar *options;
+};
+
+typedef struct _UDisksCrypttabEntryClass UDisksCrypttabEntryClass;
+
+struct _UDisksCrypttabEntryClass
+{
+  GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (UDisksCrypttabEntry, udisks_crypttab_entry, G_TYPE_OBJECT);
+
+static void
+udisks_crypttab_entry_finalize (GObject *object)
+{
+  UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (object);
+
+  g_free (entry->name);
+  g_free (entry->device);
+  g_free (entry->passphrase_path);
+  g_free (entry->options);
+
+  if (G_OBJECT_CLASS (udisks_crypttab_entry_parent_class)->finalize)
+    G_OBJECT_CLASS (udisks_crypttab_entry_parent_class)->finalize (object);
+}
+
+static void
+udisks_crypttab_entry_init (UDisksCrypttabEntry *crypttab_entry)
+{
+}
+
+static void
+udisks_crypttab_entry_class_init (UDisksCrypttabEntryClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = udisks_crypttab_entry_finalize;
+}
+
+UDisksCrypttabEntry *
+_udisks_crypttab_entry_new (const gchar *name,
+                            const gchar *device,
+                            const gchar *passphrase_path,
+                            const gchar *options)
+{
+  UDisksCrypttabEntry *entry;
+
+  entry = UDISKS_CRYPTTAB_ENTRY (g_object_new (UDISKS_TYPE_CRYPTTAB_ENTRY, NULL));
+  entry->name = g_strdup (name);
+  entry->device = g_strdup (device);
+  entry->passphrase_path = g_strdup (passphrase_path);
+  entry->options = g_strdup (options);
+
+  return entry;
+}
+
+/**
+ * udisks_crypttab_entry_compare:
+ * @entry: A #UDisksCrypttabEntry
+ * @other_entry: Another #UDisksCrypttabEntry.
+ *
+ * Comparison function for comparing two #UDisksCrypttabEntry objects.
+ *
+ * Returns: Negative value if @entry < @other_entry; zero if @entry = @other_entry; positive value if @entry > @other_entry.
+ */
+gint
+udisks_crypttab_entry_compare (UDisksCrypttabEntry  *entry,
+                               UDisksCrypttabEntry  *other_entry)
+{
+  gint ret;
+
+  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_ENTRY (entry), 0);
+  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_ENTRY (other_entry), 0);
+
+  ret = g_strcmp0 (other_entry->name, entry->name);
+  if (ret != 0)
+    goto out;
+
+  ret = g_strcmp0 (other_entry->device, entry->device);
+  if (ret != 0)
+    goto out;
+
+  ret = g_strcmp0 (other_entry->passphrase_path, entry->passphrase_path);
+  if (ret != 0)
+    goto out;
+
+  ret = g_strcmp0 (other_entry->options, entry->options);
+
+ out:
+  return ret;
+}
+
+/**
+ * udisks_crypttab_entry_get_name:
+ * @entry: A #UDisksCrypttabEntry.
+ *
+ * Gets the name field of @entry.
+ *
+ * Returns: The name field.
+ */
+const gchar *
+udisks_crypttab_entry_get_name (UDisksCrypttabEntry *entry)
+{
+  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_ENTRY (entry), NULL);
+  return entry->name;
+}
+
+/**
+ * udisks_crypttab_entry_get_device:
+ * @entry: A #UDisksCrypttabEntry.
+ *
+ * Gets the device field of @entry.
+ *
+ * Returns: The device field.
+ */
+const gchar *
+udisks_crypttab_entry_get_device (UDisksCrypttabEntry *entry)
+{
+  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_ENTRY (entry), NULL);
+  return entry->device;
+}
+
+/**
+ * udisks_crypttab_entry_get_passphrase_path:
+ * @entry: A #UDisksCrypttabEntry.
+ *
+ * Gets the passphrase path field of @entry.
+ *
+ * Returns: The passphrase path field.
+ */
+const gchar *
+udisks_crypttab_entry_get_passphrase_path (UDisksCrypttabEntry *entry)
+{
+  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_ENTRY (entry), NULL);
+  return entry->passphrase_path;
+}
+
+/**
+ * udisks_crypttab_entry_get_options:
+ * @entry: A #UDisksCrypttabEntry.
+ *
+ * Gets the options field of @entry.
+ *
+ * Returns: The options field.
+ */
+const gchar *
+udisks_crypttab_entry_get_options (UDisksCrypttabEntry *entry)
+{
+  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_ENTRY (entry), NULL);
+  return entry->options;
+}
+
diff --git a/src/udiskscrypttabentry.h b/src/udiskscrypttabentry.h
new file mode 100644 (file)
index 0000000..f1b8734
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <zeuthen@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __UDISKS_CRYPTTAB_ENTRY_H__
+#define __UDISKS_CRYPTTAB_ENTRY_H__
+
+#include "udisksdaemontypes.h"
+
+G_BEGIN_DECLS
+
+#define UDISKS_TYPE_CRYPTTAB_ENTRY         (udisks_crypttab_entry_get_type ())
+#define UDISKS_CRYPTTAB_ENTRY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_CRYPTTAB_ENTRY, UDisksCrypttabEntry))
+#define UDISKS_IS_CRYPTTAB_ENTRY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_CRYPTTAB_ENTRY))
+
+GType            udisks_crypttab_entry_get_type            (void) G_GNUC_CONST;
+const gchar     *udisks_crypttab_entry_get_name            (UDisksCrypttabEntry *entry);
+const gchar     *udisks_crypttab_entry_get_device          (UDisksCrypttabEntry *entry);
+const gchar     *udisks_crypttab_entry_get_passphrase_path (UDisksCrypttabEntry *entry);
+const gchar     *udisks_crypttab_entry_get_options         (UDisksCrypttabEntry *entry);
+gint             udisks_crypttab_entry_compare             (UDisksCrypttabEntry *entry,
+                                                            UDisksCrypttabEntry *other_entry);
+
+G_END_DECLS
+
+#endif /* __UDISKS_CRYPTTAB_ENTRY_H__ */
diff --git a/src/udiskscrypttabmonitor.c b/src/udiskscrypttabmonitor.c
new file mode 100644 (file)
index 0000000..f3b54ea
--- /dev/null
@@ -0,0 +1,444 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <zeuthen@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "udiskscrypttabmonitor.h"
+#include "udiskscrypttabentry.h"
+#include "udisksprivate.h"
+#include "udiskslogging.h"
+
+/**
+ * SECTION:udiskscrypttabmonitor
+ * @title: UDisksCrypttabMonitor
+ * @short_description: Monitors entries in the crypttab file
+ *
+ * This type is used for monitoring entries in the
+ * <filename>/etc/crypttab</filename> file.
+ */
+
+/**
+ * UDisksCrypttabMonitor:
+ *
+ * The #UDisksCrypttabMonitor structure contains only private data and
+ * should only be accessed using the provided API.
+ */
+struct _UDisksCrypttabMonitor
+{
+  GObject parent_instance;
+
+  gboolean have_data;
+  GList *crypttab_entries;
+
+  GFileMonitor *file_monitor;
+};
+
+typedef struct _UDisksCrypttabMonitorClass UDisksCrypttabMonitorClass;
+
+struct _UDisksCrypttabMonitorClass
+{
+  GObjectClass parent_class;
+
+  void (*entry_added)   (UDisksCrypttabMonitor  *monitor,
+                         UDisksCrypttabEntry    *entry);
+  void (*entry_removed) (UDisksCrypttabMonitor  *monitor,
+                         UDisksCrypttabEntry    *entry);
+};
+
+/*--------------------------------------------------------------------------------------------------------------*/
+
+enum
+  {
+    ENTRY_ADDED_SIGNAL,
+    ENTRY_REMOVED_SIGNAL,
+    LAST_SIGNAL,
+  };
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (UDisksCrypttabMonitor, udisks_crypttab_monitor, G_TYPE_OBJECT)
+
+static void udisks_crypttab_monitor_ensure (UDisksCrypttabMonitor *monitor);
+static void udisks_crypttab_monitor_invalidate (UDisksCrypttabMonitor *monitor);
+static void udisks_crypttab_monitor_constructed (GObject *object);
+
+static void
+udisks_crypttab_monitor_finalize (GObject *object)
+{
+  UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (object);
+
+  g_object_unref (monitor->file_monitor);
+
+  g_list_foreach (monitor->crypttab_entries, (GFunc) g_object_unref, NULL);
+  g_list_free (monitor->crypttab_entries);
+
+  if (G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->finalize != NULL)
+    G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->finalize (object);
+}
+
+static void
+udisks_crypttab_monitor_init (UDisksCrypttabMonitor *monitor)
+{
+  monitor->crypttab_entries = NULL;
+}
+
+static void
+udisks_crypttab_monitor_class_init (UDisksCrypttabMonitorClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->finalize    = udisks_crypttab_monitor_finalize;
+  gobject_class->constructed = udisks_crypttab_monitor_constructed;
+
+  /**
+   * UDisksCrypttabMonitor::entry-added
+   * @monitor: A #UDisksCrypttabMonitor.
+   * @entry: The #UDisksCrypttabEntry that was added.
+   *
+   * Emitted when a crypttab entry is added.
+   *
+   * This signal is emitted in the
+   * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+   * that @monitor was created in.
+   */
+  signals[ENTRY_ADDED_SIGNAL] = g_signal_new ("entry-added",
+                                              G_OBJECT_CLASS_TYPE (klass),
+                                              G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                                              G_STRUCT_OFFSET (UDisksCrypttabMonitorClass, entry_added),
+                                              NULL,
+                                              NULL,
+                                              g_cclosure_marshal_VOID__OBJECT,
+                                              G_TYPE_NONE,
+                                              1,
+                                              UDISKS_TYPE_CRYPTTAB_ENTRY);
+
+  /**
+   * UDisksCrypttabMonitor::entry-removed
+   * @monitor: A #UDisksCrypttabMonitor.
+   * @entry: The #UDisksCrypttabEntry that was removed.
+   *
+   * Emitted when a crypttab entry is removed.
+   *
+   * This signal is emitted in the
+   * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+   * that @monitor was created in.
+   */
+  signals[ENTRY_REMOVED_SIGNAL] = g_signal_new ("entry-removed",
+                                                G_OBJECT_CLASS_TYPE (klass),
+                                                G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                                                G_STRUCT_OFFSET (UDisksCrypttabMonitorClass, entry_removed),
+                                                NULL,
+                                                NULL,
+                                                g_cclosure_marshal_VOID__OBJECT,
+                                                G_TYPE_NONE,
+                                                1,
+                                                UDISKS_TYPE_CRYPTTAB_ENTRY);
+}
+
+static void
+diff_sorted_lists (GList *list1,
+                   GList *list2,
+                   GCompareFunc compare,
+                   GList **added,
+                   GList **removed)
+{
+  int order;
+
+  *added = *removed = NULL;
+
+  while (list1 != NULL && list2 != NULL)
+    {
+      order = (*compare) (list1->data, list2->data);
+      if (order < 0)
+        {
+          *removed = g_list_prepend (*removed, list1->data);
+          list1 = list1->next;
+        }
+      else if (order > 0)
+        {
+          *added = g_list_prepend (*added, list2->data);
+          list2 = list2->next;
+        }
+      else
+        { /* same item */
+          list1 = list1->next;
+          list2 = list2->next;
+        }
+    }
+
+  while (list1 != NULL)
+    {
+      *removed = g_list_prepend (*removed, list1->data);
+      list1 = list1->next;
+    }
+  while (list2 != NULL)
+    {
+      *added = g_list_prepend (*added, list2->data);
+      list2 = list2->next;
+    }
+}
+
+static void
+reload_crypttab_entries (UDisksCrypttabMonitor *monitor)
+{
+  GList *old_crypttab_entries;
+  GList *cur_crypttab_entries;
+  GList *added;
+  GList *removed;
+  GList *l;
+
+  udisks_crypttab_monitor_ensure (monitor);
+
+  old_crypttab_entries = g_list_copy (monitor->crypttab_entries);
+  g_list_foreach (old_crypttab_entries, (GFunc) g_object_ref, NULL);
+
+  udisks_crypttab_monitor_invalidate (monitor);
+  udisks_crypttab_monitor_ensure (monitor);
+
+  cur_crypttab_entries = g_list_copy (monitor->crypttab_entries);
+
+  old_crypttab_entries = g_list_sort (old_crypttab_entries, (GCompareFunc) udisks_crypttab_entry_compare);
+  cur_crypttab_entries = g_list_sort (cur_crypttab_entries, (GCompareFunc) udisks_crypttab_entry_compare);
+  diff_sorted_lists (old_crypttab_entries, cur_crypttab_entries, (GCompareFunc) udisks_crypttab_entry_compare, &added, &removed);
+
+  for (l = removed; l != NULL; l = l->next)
+    {
+      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
+      g_signal_emit (monitor, signals[ENTRY_REMOVED_SIGNAL], 0, entry);
+    }
+
+  for (l = added; l != NULL; l = l->next)
+    {
+      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
+      g_signal_emit (monitor, signals[ENTRY_ADDED_SIGNAL], 0, entry);
+    }
+
+  g_list_foreach (old_crypttab_entries, (GFunc) g_object_unref, NULL);
+  g_list_free (old_crypttab_entries);
+  g_list_free (cur_crypttab_entries);
+  g_list_free (removed);
+  g_list_free (added);
+}
+
+static void
+on_file_monitor_changed (GFileMonitor      *file_monitor,
+                         GFile             *file,
+                         GFile             *other_file,
+                         GFileMonitorEvent  event_type,
+                         gpointer           user_data)
+{
+  UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (user_data);
+  if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
+      event_type == G_FILE_MONITOR_EVENT_CREATED)
+    {
+      udisks_debug ("/etc/crypttab changed!");
+      reload_crypttab_entries (monitor);
+    }
+}
+
+static void
+udisks_crypttab_monitor_constructed (GObject *object)
+{
+  UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (object);
+  GError *error;
+  GFile *file;
+
+  file = g_file_new_for_path ("/etc/crypttab");
+  error = NULL;
+  monitor->file_monitor = g_file_monitor_file (file,
+                                               G_FILE_MONITOR_NONE,
+                                               NULL, /* cancellable */
+                                               &error);
+  if (monitor->file_monitor == NULL)
+    {
+      udisks_error ("Error monitoring /etc/crypttab: %s (%s, %d)",
+                    error->message, g_quark_to_string (error->domain), error->code);
+      g_error_free (error);
+    }
+  else
+    {
+      g_signal_connect (monitor->file_monitor,
+                        "changed",
+                        G_CALLBACK (on_file_monitor_changed),
+                        monitor);
+    }
+  g_object_unref (file);
+
+  if (G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->constructed != NULL)
+    (*G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->constructed) (object);
+}
+
+/**
+ * udisks_crypttab_monitor_new:
+ *
+ * Creates a new #UDisksCrypttabMonitor object.
+ *
+ * Signals are emitted in the <link
+ * linkend="g-main-context-push-thread-default">thread-default main
+ * loop</link> that this function is called from.
+ *
+ * Returns: A #UDisksCrypttabMonitor. Free with g_object_unref().
+ */
+UDisksCrypttabMonitor *
+udisks_crypttab_monitor_new (void)
+{
+  return UDISKS_CRYPTTAB_MONITOR (g_object_new (UDISKS_TYPE_CRYPTTAB_MONITOR, NULL));
+}
+
+static void
+udisks_crypttab_monitor_invalidate (UDisksCrypttabMonitor *monitor)
+{
+  monitor->have_data = FALSE;
+
+  g_list_foreach (monitor->crypttab_entries, (GFunc) g_object_unref, NULL);
+  g_list_free (monitor->crypttab_entries);
+  monitor->crypttab_entries = NULL;
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+have_entry (UDisksCrypttabMonitor *monitor,
+            UDisksCrypttabEntry   *entry)
+{
+  GList *l;
+  gboolean ret;
+
+  ret = FALSE;
+  for (l = monitor->crypttab_entries; l != NULL; l = l->next)
+    {
+      UDisksCrypttabEntry *other_entry = UDISKS_CRYPTTAB_ENTRY (l->data);
+      if (udisks_crypttab_entry_compare (entry, other_entry) == 0)
+        {
+          ret = TRUE;
+          goto out;
+        }
+    }
+ out:
+  return ret;
+}
+
+static void
+udisks_crypttab_monitor_ensure (UDisksCrypttabMonitor *monitor)
+{
+  gchar *contents;
+  gchar **lines;
+  GError *error;
+  guint n;
+
+  contents = NULL;
+  lines = NULL;
+
+  if (monitor->have_data)
+    goto out;
+
+  error = NULL;
+  if (!g_file_get_contents ("/etc/crypttab",
+                            &contents,
+                            NULL, /* size */
+                            &error))
+    {
+      udisks_warning ("Error opening /etc/crypttab file: %s (%s, %d)",
+                      error->message, g_quark_to_string (error->domain), error->code);
+      g_error_free (error);
+      goto out;
+    }
+
+  lines = g_strsplit (contents, "\n", 0);
+
+  for (n = 0; lines != NULL && lines[n] != NULL; n++)
+    {
+      gchar **tokens;
+      guint num_tokens;
+      UDisksCrypttabEntry *entry;
+
+      const gchar *line = lines[n];
+      if (strlen (line) == 0)
+        continue;
+      if (line[0] == '#')
+        continue;
+
+      tokens = g_strsplit_set (line, " \t", 0);
+      num_tokens = g_strv_length (tokens);
+      if (num_tokens < 2)
+        {
+          udisks_warning ("Line %d of /etc/crypttab only contains %d tokens", n, num_tokens);
+          goto continue_loop;
+        }
+
+      entry = _udisks_crypttab_entry_new (tokens[0],
+                                          tokens[1],
+                                          num_tokens >= 3 ? tokens[2] : NULL,
+                                          num_tokens >= 4 ? tokens[3] : NULL);
+      if (!have_entry (monitor, entry))
+        {
+          monitor->crypttab_entries = g_list_prepend (monitor->crypttab_entries, entry);
+        }
+      else
+        {
+          g_object_unref (entry);
+        }
+
+    continue_loop:
+      g_strfreev (tokens);
+    }
+
+  monitor->have_data = TRUE;
+
+ out:
+  g_free (contents);
+  g_strfreev (lines);
+}
+
+/**
+ * udisks_crypttab_monitor_get_entries:
+ * @monitor: A #UDisksCrypttabMonitor.
+ *
+ * Gets all /etc/crypttab entries
+ *
+ * Returns: (transfer full) (element-type UDisksCrypttabEntry): A list of #UDisksCrypttabEntry objects that must be freed with g_list_free() after each element has been freed with g_object_unref().
+ */
+GList *
+udisks_crypttab_monitor_get_entries (UDisksCrypttabMonitor  *monitor)
+{
+  GList *ret;
+
+  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_MONITOR (monitor), NULL);
+
+  udisks_crypttab_monitor_ensure (monitor);
+
+  ret = g_list_copy (monitor->crypttab_entries);
+  g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+  return ret;
+}
+
diff --git a/src/udiskscrypttabmonitor.h b/src/udiskscrypttabmonitor.h
new file mode 100644 (file)
index 0000000..837bc4c
--- /dev/null
@@ -0,0 +1,38 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <zeuthen@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __UDISKS_CRYPTTAB_MONITOR_H__
+#define __UDISKS_CRYPTTAB_MONITOR_H__
+
+#include "udisksdaemontypes.h"
+
+G_BEGIN_DECLS
+
+#define UDISKS_TYPE_CRYPTTAB_MONITOR  (udisks_crypttab_monitor_get_type ())
+#define UDISKS_CRYPTTAB_MONITOR(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_CRYPTTAB_MONITOR, UDisksCrypttabMonitor))
+#define UDISKS_IS_CRYPTTAB_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_CRYPTTAB_MONITOR))
+
+GType                   udisks_crypttab_monitor_get_type    (void) G_GNUC_CONST;
+UDisksCrypttabMonitor  *udisks_crypttab_monitor_new         (void);
+GList                  *udisks_crypttab_monitor_get_entries (UDisksCrypttabMonitor  *monitor);
+
+G_END_DECLS
+
+#endif /* __UDISKS_CRYPTTAB_MONITOR_H__ */
index 3b72b26..4532746 100644 (file)
@@ -35,6 +35,8 @@
 #include "udiskscleanup.h"
 #include "udisksfstabmonitor.h"
 #include "udisksfstabentry.h"
+#include "udiskscrypttabmonitor.h"
+#include "udiskscrypttabentry.h"
 
 /**
  * SECTION:udisksdaemon
@@ -69,6 +71,8 @@ struct _UDisksDaemon
   UDisksCleanup *cleanup;
 
   UDisksFstabMonitor *fstab_monitor;
+
+  UDisksCrypttabMonitor *crypttab_monitor;
 };
 
 struct _UDisksDaemonClass
@@ -83,6 +87,7 @@ enum
   PROP_OBJECT_MANAGER,
   PROP_MOUNT_MONITOR,
   PROP_FSTAB_MONITOR,
+  PROP_CRYPTTAB_MONITOR,
 };
 
 G_DEFINE_TYPE (UDisksDaemon, udisks_daemon, G_TYPE_OBJECT);
@@ -102,6 +107,7 @@ udisks_daemon_finalize (GObject *object)
   g_object_unref (daemon->mount_monitor);
   g_object_unref (daemon->connection);
   g_object_unref (daemon->fstab_monitor);
+  g_object_unref (daemon->crypttab_monitor);
 
   if (G_OBJECT_CLASS (udisks_daemon_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (udisks_daemon_parent_class)->finalize (object);
@@ -133,6 +139,10 @@ udisks_daemon_get_property (GObject    *object,
       g_value_set_object (value, udisks_daemon_get_fstab_monitor (daemon));
       break;
 
+    case PROP_CRYPTTAB_MONITOR:
+      g_value_set_object (value, udisks_daemon_get_crypttab_monitor (daemon));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -218,6 +228,7 @@ udisks_daemon_constructed (GObject *object)
                     daemon);
 
   daemon->fstab_monitor = udisks_fstab_monitor_new ();
+  daemon->crypttab_monitor = udisks_crypttab_monitor_new ();
 
   /* now add providers */
   daemon->linux_provider = udisks_linux_provider_new (daemon);
@@ -371,6 +382,21 @@ udisks_daemon_get_fstab_monitor (UDisksDaemon *daemon)
 }
 
 /**
+ * udisks_daemon_get_crypttab_monitor:
+ * @daemon: A #UDisksDaemon
+ *
+ * Gets the crypttab monitor used by @daemon.
+ *
+ * Returns: A #UDisksCrypttabMonitor. Do not free, the object is owned by @daemon.
+ */
+UDisksCrypttabMonitor *
+udisks_daemon_get_crypttab_monitor (UDisksDaemon *daemon)
+{
+  g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
+  return daemon->crypttab_monitor;
+}
+
+/**
  * udisks_daemon_get_linux_provider:
  * @daemon: A #UDisksDaemon.
  *
index 684e673..56bbdaf 100644 (file)
@@ -35,6 +35,7 @@ GDBusConnection          *udisks_daemon_get_connection        (UDisksDaemon    *
 GDBusObjectManagerServer *udisks_daemon_get_object_manager    (UDisksDaemon    *daemon);
 UDisksMountMonitor       *udisks_daemon_get_mount_monitor     (UDisksDaemon    *daemon);
 UDisksFstabMonitor       *udisks_daemon_get_fstab_monitor     (UDisksDaemon    *daemon);
+UDisksCrypttabMonitor    *udisks_daemon_get_crypttab_monitor  (UDisksDaemon    *daemon);
 UDisksLinuxProvider      *udisks_daemon_get_linux_provider    (UDisksDaemon    *daemon);
 UDisksPersistentStore    *udisks_daemon_get_persistent_store  (UDisksDaemon    *daemon);
 PolkitAuthority          *udisks_daemon_get_authority         (UDisksDaemon    *daemon);
index fe4b1ba..edf97c2 100644 (file)
@@ -82,6 +82,12 @@ typedef struct _UDisksFstabMonitor UDisksFstabMonitor;
 struct _UDisksFstabEntry;
 typedef struct _UDisksFstabEntry UDisksFstabEntry;
 
+struct _UDisksCrypttabMonitor;
+typedef struct _UDisksCrypttabMonitor UDisksCrypttabMonitor;
+
+struct _UDisksCrypttabEntry;
+typedef struct _UDisksCrypttabEntry UDisksCrypttabEntry;
+
 /**
  * UDisksThreadedJobFunc:
  * @job: A #UDisksThreadedJob.
index 027c940..d8cfe23 100644 (file)
@@ -45,6 +45,8 @@
 #include "udiskslinuxprovider.h"
 #include "udisksfstabmonitor.h"
 #include "udisksfstabentry.h"
+#include "udiskscrypttabmonitor.h"
+#include "udiskscrypttabentry.h"
 
 /**
  * SECTION:udiskslinuxblock
@@ -371,6 +373,48 @@ update_iface (UDisksLinuxBlock           *block,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static GVariant *calculate_configuration (UDisksLinuxBlock  *block,
+                                          gboolean           include_secrets,
+                                          GError           **error);
+
+static gboolean
+on_get_secret_configuration (UDisksBlockDevice     *block,
+                             GDBusMethodInvocation *invocation,
+                             GVariant              *options,
+                             gpointer               user_data)
+{
+  UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data);
+  GVariant *configuration;
+  GError *error;
+
+  error = NULL;
+  configuration = calculate_configuration (object, TRUE, &error);
+  if (configuration == NULL)
+    {
+      g_dbus_method_invocation_take_error (invocation, error);
+      goto out;
+    }
+
+  if (!udisks_daemon_util_check_authorization_sync (object->daemon,
+                                                    NULL,
+                                                    "org.freedesktop.udisks2.read-system-configuration-secrets",
+                                                    options,
+                                                    N_("Authentication is required to read system-level secrets"),
+                                                    invocation))
+    {
+      g_variant_unref (configuration);
+      goto out;
+    }
+
+  udisks_block_device_complete_get_secret_configuration (object->iface_block_device, invocation,
+                                                         configuration); /* consumes floating ref */
+
+ out:
+  return TRUE; /* returning TRUE means that we handled the method invocation */
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gchar *
 escape_fstab (const gchar *source)
 {
@@ -442,8 +486,8 @@ out:
 }
 
 static gboolean
-add_remove_fstab_entry (GVariant  *add,
-                        GVariant  *remove,
+add_remove_fstab_entry (GVariant  *remove,
+                        GVariant  *add,
                         GError   **error)
 {
   struct mntent mntent_remove;
@@ -598,6 +642,252 @@ add_remove_fstab_entry (GVariant  *add,
   return ret;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+has_whitespace (const gchar *s)
+{
+  guint n;
+  g_return_val_if_fail (s != NULL, TRUE);
+  for (n = 0; s[n] != '\0'; n++)
+    if (g_ascii_isspace (s[n]))
+      return TRUE;
+  return FALSE;
+}
+
+static gboolean
+add_remove_crypttab_entry (GVariant  *remove,
+                           GVariant  *add,
+                           GError   **error)
+{
+  const gchar *remove_name = NULL;
+  const gchar *remove_device = NULL;
+  const gchar *remove_passphrase_path = NULL;
+  const gchar *remove_options = NULL;
+  const gchar *add_name = NULL;
+  const gchar *add_device = NULL;
+  const gchar *add_passphrase_path = NULL;
+  const gchar *add_options = NULL;
+  const gchar *add_passphrase_contents = NULL;
+  gboolean ret;
+  gchar *contents;
+  gchar **lines;
+  GString *str;
+  gboolean removed;
+  guint n;
+
+  contents = NULL;
+  lines = NULL;
+  str = NULL;
+  ret = FALSE;
+
+  if (remove != NULL)
+    {
+      if (!g_variant_lookup (remove, "name", "^&ay", &remove_name) ||
+          !g_variant_lookup (remove, "device", "^&ay", &remove_device) ||
+          !g_variant_lookup (remove, "passphrase-path", "^&ay", &remove_passphrase_path) ||
+          !g_variant_lookup (remove, "options", "^&ay", &remove_options))
+        {
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "Missing name, device, passphrase-path, options or parameter in entry to remove");
+          goto out;
+        }
+    }
+
+  if (add != NULL)
+    {
+      if (!g_variant_lookup (add, "name", "^&ay", &add_name) ||
+          !g_variant_lookup (add, "device", "^&ay", &add_device) ||
+          !g_variant_lookup (add, "passphrase-path", "^&ay", &add_passphrase_path) ||
+          !g_variant_lookup (add, "options", "^&ay", &add_options) ||
+          !g_variant_lookup (add, "passphrase-contents", "^&ay", &add_passphrase_contents))
+        {
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "Missing name, device, passphrase-path, options or passphrase-contents parameter in entry to add");
+          goto out;
+        }
+
+      /* reject strings with whitespace in them */
+      if (has_whitespace (add_name) ||
+          has_whitespace (add_device) ||
+          has_whitespace (add_passphrase_path) ||
+          has_whitespace (add_options))
+        {
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "One of name, device, passphrase-path or options parameter are invalid (whitespace)");
+          goto out;
+        }
+    }
+
+  if (!g_file_get_contents ("/etc/crypttab",
+                            &contents,
+                            NULL,
+                            error))
+    goto out;
+
+  lines = g_strsplit (contents, "\n", 0);
+
+  str = g_string_new (NULL);
+  removed = FALSE;
+  for (n = 0; lines != NULL && lines[n] != NULL; n++)
+    {
+      const gchar *line = lines[n];
+      if (strlen (line) == 0 && lines[n+1] == NULL)
+        break;
+      if (remove != NULL && !removed)
+        {
+          gchar parsed_name[512];
+          gchar parsed_device[512];
+          gchar parsed_passphrase_path[512];
+          gchar parsed_options[512];
+          guint num_parsed;
+
+          num_parsed = sscanf (line, "%511s %511s %511s %511s",
+                               parsed_name, parsed_device, parsed_passphrase_path, parsed_options);
+          if (num_parsed >= 2)
+            {
+              if (num_parsed < 3 || g_strcmp0 (parsed_passphrase_path, "none") == 0)
+                strcpy (parsed_passphrase_path, "");
+              if (num_parsed < 4)
+                strcpy (parsed_options, "");
+              if (g_strcmp0 (parsed_name,            remove_name) == 0 &&
+                  g_strcmp0 (parsed_device,          remove_device) == 0 &&
+                  g_strcmp0 (parsed_passphrase_path, remove_passphrase_path) == 0 &&
+                  g_strcmp0 (parsed_options,         remove_options) == 0)
+                {
+                  /* Nuke passphrase file */
+                  if (strlen (remove_passphrase_path) > 0 && !g_str_has_prefix (remove_passphrase_path, "/dev"))
+                    {
+                      /* Is this exploitable? No, 1. the user would have to control
+                       * the /etc/crypttab file for us to delete it; and 2. editing the
+                       * /etc/crypttab file requires a polkit authorization that can't
+                       * be retained (e.g. the user is always asked for the password)..
+                       */
+                      if (unlink (remove_passphrase_path) != 0)
+                        {
+                          g_set_error (error,
+                                       UDISKS_ERROR,
+                                       UDISKS_ERROR_FAILED,
+                                       "Error deleting file `%s' with passphrase",
+                                       remove_passphrase_path);
+                          goto out;
+                        }
+                    }
+                  removed = TRUE;
+                  continue;
+                }
+            }
+        }
+      g_string_append (str, line);
+      g_string_append_c (str, '\n');
+    }
+
+  if (remove != NULL && !removed)
+    {
+      g_set_error (error,
+                   UDISKS_ERROR,
+                   UDISKS_ERROR_FAILED,
+                   "Didn't find entry to remove");
+      goto out;
+    }
+
+  if (add != NULL)
+    {
+      /* First write add_passphrase_content to add_passphrase_path,
+       * if applicable..
+       *
+       * Is this exploitable? No, because editing the /etc/crypttab
+       * file requires a polkit authorization that can't be retained
+       * (e.g. the user is always asked for the password)...
+       *
+       * Just to be on the safe side we only allow writing into the
+       * directory /etc/luks-keys if create a _new_ entry.
+       */
+      if (strlen (add_passphrase_path) > 0)
+        {
+          gchar *filename;
+          if (g_strcmp0 (add_passphrase_path, remove_passphrase_path) == 0)
+            {
+              filename = g_strdup (add_passphrase_path);
+            }
+          else
+            {
+              if (!g_str_has_prefix (add_passphrase_path, "/etc/luks-keys/"))
+                {
+                  g_set_error (error,
+                               UDISKS_ERROR,
+                               UDISKS_ERROR_FAILED,
+                               "Crypttab passphrase file can only be created in the /etc/luks-keys directory");
+                  goto out;
+                }
+              /* ensure the directory exists */
+              if (g_mkdir_with_parents ("/etc/luks-keys", 0700) != 0)
+                {
+                  g_set_error (error,
+                               UDISKS_ERROR,
+                               UDISKS_ERROR_FAILED,
+                               "Error creating /etc/luks-keys directory: %m");
+                  goto out;
+                }
+              /* avoid symlink attacks */
+              filename = g_strdup_printf ("/etc/luks-keys/%s", strrchr (add_passphrase_path, '/') + 1);
+            }
+
+          /* Bail if the requested file already exists */
+          if (g_file_test (filename, G_FILE_TEST_EXISTS))
+            {
+                  g_set_error (error,
+                               UDISKS_ERROR,
+                               UDISKS_ERROR_FAILED,
+                               "Refusing to overwrite existing file %s",
+                               filename);
+                  g_free (filename);
+                  goto out;
+            }
+
+          /* TODO: XXX: would like to use mode 0600 here - umask(3) at start-up? */
+          if (!g_file_set_contents (filename,
+                                    add_passphrase_contents,
+                                    -1,
+                                    error))
+            {
+              g_free (filename);
+              goto out;
+            }
+          g_free (filename);
+        }
+      g_string_append_printf (str, "%s %s %s %s\n",
+                              add_name,
+                              add_device,
+                              strlen (add_passphrase_path) > 0 ? add_passphrase_path : "none",
+                              add_options);
+    }
+
+  /* TODO: XXX: ugh, the mode is wrong.. umask(3) at start-up? */
+  if (!g_file_set_contents ("/etc/crypttab",
+                            str->str,
+                            -1,
+                            error) != 0)
+    goto out;
+
+  ret = TRUE;
+
+ out:
+  g_strfreev (lines);
+  g_free (contents);
+  if (str != NULL)
+    g_string_free (str, TRUE);
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gboolean
 on_add_configuration_item (UDisksBlockDevice     *block,
                            GDBusMethodInvocation *invocation,
@@ -612,32 +902,49 @@ on_add_configuration_item (UDisksBlockDevice     *block,
 
   g_variant_get (item, "(&s@a{sv})", &type, &details);
 
-  if (g_strcmp0 (type, "fstab") != 0)
+  if (g_strcmp0 (type, "fstab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to add an entry to the /etc/fstab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_fstab_entry (NULL, details, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (block, invocation);
+    }
+  else if (g_strcmp0 (type, "crypttab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to add an entry to the /etc/crypttab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_crypttab_entry (NULL, details, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (block, invocation);
+    }
+  else
     {
       g_dbus_method_invocation_return_error (invocation,
                                              UDISKS_ERROR,
                                              UDISKS_ERROR_FAILED,
-                                             "Only fstab items can be added");
+                                             "Only /etc/fstab or /etc/crypttab items can be added");
       goto out;
     }
 
-  if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                    NULL,
-                                                    "org.freedesktop.udisks2.modify-system-configuration",
-                                                    options,
-                                                    N_("Authentication is required to modify the /etc/fstab file"),
-                                                    invocation))
-    goto out;
-
-  error = NULL;
-  if (!add_remove_fstab_entry (details, NULL, &error))
-    {
-      g_dbus_method_invocation_take_error (invocation, error);
-      goto out;
-    }
-
-  udisks_block_device_complete_add_configuration_item (block, invocation);
-
  out:
   g_variant_unref (details);
   return TRUE; /* returning TRUE means that we handled the method invocation */
@@ -657,34 +964,126 @@ on_remove_configuration_item (UDisksBlockDevice     *block,
 
   g_variant_get (item, "(&s@a{sv})", &type, &details);
 
-  if (g_strcmp0 (type, "fstab") != 0)
+  if (g_strcmp0 (type, "fstab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to remove an entry from /etc/fstab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_fstab_entry (details, NULL, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (block, invocation);
+    }
+  else if (g_strcmp0 (type, "crypttab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to remove an entry from the /etc/crypttab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_crypttab_entry (details, NULL, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (block, invocation);
+    }
+  else
     {
       g_dbus_method_invocation_return_error (invocation,
                                              UDISKS_ERROR,
                                              UDISKS_ERROR_FAILED,
-                                             "Only fstab items can be removed");
+                                             "Only fstab or crypttab items can be removed");
       goto out;
     }
 
-  if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                    NULL,
-                                                    "org.freedesktop.udisks2.modify-system-configuration",
-                                                    options,
-                                                    N_("Authentication is required to modify the /etc/fstab file"),
-                                                    invocation))
-    goto out;
+ out:
+  g_variant_unref (details);
+  return TRUE; /* returning TRUE means that we handled the method invocation */
+}
 
-  error = NULL;
-  if (!add_remove_fstab_entry (NULL, details, &error))
+static gboolean
+on_update_configuration_item (UDisksBlockDevice     *block,
+                              GDBusMethodInvocation *invocation,
+                              GVariant              *old_item,
+                              GVariant              *new_item,
+                              GVariant              *options,
+                              gpointer               user_data)
+{
+  UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data);
+  const gchar *old_type;
+  const gchar *new_type;
+  GVariant *old_details;
+  GVariant *new_details;
+  GError *error;
+
+  g_variant_get (old_item, "(&s@a{sv})", &old_type, &old_details);
+  g_variant_get (new_item, "(&s@a{sv})", &new_type, &new_details);
+  if (g_strcmp0 (old_type, new_type) != 0)
     {
-      g_dbus_method_invocation_take_error (invocation, error);
+      g_dbus_method_invocation_return_error (invocation,
+                                             UDISKS_ERROR,
+                                             UDISKS_ERROR_FAILED,
+                                             "old and new item are not of the same type");
       goto out;
     }
 
-  udisks_block_device_complete_add_configuration_item (block, invocation);
+  if (g_strcmp0 (old_type, "fstab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to modify the /etc/fstab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_fstab_entry (old_details, new_details, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (block, invocation);
+    }
+  else if (g_strcmp0 (old_type, "crypttab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to modify the /etc/crypttab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_crypttab_entry (old_details, new_details, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (block, invocation);
+    }
+  else
+    {
+      g_dbus_method_invocation_return_error (invocation,
+                                             UDISKS_ERROR,
+                                             UDISKS_ERROR_FAILED,
+                                             "Only fstab or crypttab items can be updated");
+      goto out;
+    }
 
  out:
-  g_variant_unref (details);
+  g_variant_unref (new_details);
+  g_variant_unref (old_details);
   return TRUE; /* returning TRUE means that we handled the method invocation */
 }
 
@@ -701,6 +1100,10 @@ static void
 block_device_connect (UDisksLinuxBlock *block)
 {
   g_signal_connect (block->iface_block_device,
+                    "handle-get-secret-configuration",
+                    G_CALLBACK (on_get_secret_configuration),
+                    block);
+  g_signal_connect (block->iface_block_device,
                     "handle-add-configuration-item",
                     G_CALLBACK (on_add_configuration_item),
                     block);
@@ -708,6 +1111,10 @@ block_device_connect (UDisksLinuxBlock *block)
                     "handle-remove-configuration-item",
                     G_CALLBACK (on_remove_configuration_item),
                     block);
+  g_signal_connect (block->iface_block_device,
+                    "handle-update-configuration-item",
+                    G_CALLBACK (on_update_configuration_item),
+                    block);
 }
 
 static gchar *
@@ -943,24 +1350,88 @@ find_fstab_entries_for_device (UDisksLinuxBlock *block)
   return ret;
 }
 
-static void
-block_device_update_configuration (UDisksLinuxBlock  *block,
-                                   const gchar       *uevent_action,
-                                   UDisksBlockDevice *iface,
-                                   const gchar       *device_file,
-                                   UDisksDrive       *drive)
+static GList *
+find_crypttab_entries_for_device (UDisksLinuxBlock *block)
+{
+  GList *entries;
+  GList *l;
+  GList *ret;
+
+  ret = NULL;
+
+  /* if this is too slow, we could add lookup methods to UDisksCrypttabMonitor... */
+  entries = udisks_crypttab_monitor_get_entries (udisks_daemon_get_crypttab_monitor (block->daemon));
+  for (l = entries; l != NULL; l = l->next)
+    {
+      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
+      const gchar *const *symlinks;
+      const gchar *device_in_entry;
+      gchar *device;
+      guint n;
+
+      device_in_entry = udisks_crypttab_entry_get_device (entry);
+      device = NULL;
+      if (g_str_has_prefix (device_in_entry, "UUID="))
+        {
+          device = g_strdup_printf ("/dev/disk/by-uuid/%s", device_in_entry + 5);
+        }
+      else if (g_str_has_prefix (device_in_entry, "LABEL="))
+        {
+          device = g_strdup_printf ("/dev/disk/by-label/%s", device_in_entry + 6);
+        }
+      else if (g_str_has_prefix (device_in_entry, "/dev"))
+        {
+          device = g_strdup (device_in_entry);
+        }
+      else
+        {
+          /* ignore non-device entries */
+          goto continue_loop;
+        }
+
+      symlinks = udisks_block_device_get_symlinks (block->iface_block_device);
+      if (symlinks != NULL)
+        {
+          for (n = 0; symlinks[n] != NULL; n++)
+            {
+              if (g_strcmp0 (device, symlinks[n]) == 0)
+                {
+                  ret = g_list_prepend (ret, g_object_ref (entry));
+                }
+            }
+        }
+
+    continue_loop:
+      g_free (device);
+    }
+
+  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+  g_list_free (entries);
+  return ret;
+}
+
+/* returns a floating GVariant */
+static GVariant *
+calculate_configuration (UDisksLinuxBlock  *block,
+                         gboolean           include_secrets,
+                         GError           **error)
 {
   GList *entries;
   GList *l;
   GVariantBuilder builder;
+  GVariant *ret;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  ret = NULL;
 
   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa{sv})"));
+  /* First the /etc/fstab entries */
   entries = find_fstab_entries_for_device (block);
   for (l = entries; l != NULL; l = l->next)
     {
       UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data);
       GVariantBuilder dict_builder;
-
       g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
       g_variant_builder_add (&dict_builder, "{sv}", "fsname",
                              g_variant_new_bytestring (udisks_fstab_entry_get_fsname (entry)));
@@ -978,12 +1449,100 @@ block_device_update_configuration (UDisksLinuxBlock  *block,
                              "(sa{sv})",
                              "fstab", &dict_builder);
     }
+  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+  g_list_free (entries);
 
-  udisks_block_device_set_configuration (block->iface_block_device,
-                                         g_variant_builder_end (&builder));
+  /* Then the /etc/crypttab entries */
+  entries = find_crypttab_entries_for_device (block);
+  for (l = entries; l != NULL; l = l->next)
+    {
+      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
+      GVariantBuilder dict_builder;
+      const gchar *passphrase_path;
+      const gchar *options;
+      gchar *passphrase_contents;
+      gsize passphrase_contents_length;
+
+      passphrase_path = udisks_crypttab_entry_get_passphrase_path (entry);
+      if (passphrase_path == NULL || g_strcmp0 (passphrase_path, "none") == 0)
+        passphrase_path = "";
+      passphrase_contents = NULL;
+      if (!(g_strcmp0 (passphrase_path, "") == 0 || g_str_has_prefix (passphrase_path, "/dev")))
+        {
+          if (include_secrets)
+            {
+              if (!g_file_get_contents (passphrase_path,
+                                        &passphrase_contents,
+                                        &passphrase_contents_length,
+                                        error))
+                {
+                  g_prefix_error (error,
+                                  "Error loading secrets from file `%s' referenced in /etc/crypttab entry: ",
+                                  passphrase_path);
+                  g_variant_builder_clear (&builder);
+                  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+                  g_list_free (entries);
+                  goto out;
+                }
+            }
+        }
 
+      options = udisks_crypttab_entry_get_options (entry);
+      if (options == NULL)
+        options = "";
+
+      g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
+      g_variant_builder_add (&dict_builder, "{sv}", "name",
+                             g_variant_new_bytestring (udisks_crypttab_entry_get_name (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "device",
+                             g_variant_new_bytestring (udisks_crypttab_entry_get_device (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "passphrase-path",
+                             g_variant_new_bytestring (passphrase_path));
+      if (passphrase_contents != NULL)
+        {
+          g_variant_builder_add (&dict_builder, "{sv}", "passphrase-contents",
+                                 g_variant_new_bytestring (passphrase_contents));
+        }
+      g_variant_builder_add (&dict_builder, "{sv}", "options",
+                             g_variant_new_bytestring (options));
+      g_variant_builder_add (&builder,
+                             "(sa{sv})",
+                             "crypttab", &dict_builder);
+      if (passphrase_contents != NULL)
+        {
+          memset (passphrase_contents, '\0', passphrase_contents_length);
+          g_free (passphrase_contents);
+        }
+    }
   g_list_foreach (entries, (GFunc) g_object_unref, NULL);
   g_list_free (entries);
+
+  ret = g_variant_builder_end (&builder);
+
+ out:
+  return ret;
+}
+
+static void
+block_device_update_configuration (UDisksLinuxBlock  *block,
+                                   const gchar       *uevent_action,
+                                   UDisksBlockDevice *iface,
+                                   const gchar       *device_file,
+                                   UDisksDrive       *drive)
+{
+  GVariant *configuration;
+  GError *error;
+
+  error = NULL;
+  configuration = calculate_configuration (block, FALSE, &error);
+  if (configuration == NULL)
+    {
+      udisks_warning ("Error loading configuration: %s (%s, %d)",
+                      error->message, g_quark_to_string (error->domain), error->code);
+      g_error_free (error);
+      configuration = g_variant_new ("a(sa{sv})", NULL);
+    }
+  udisks_block_device_set_configuration (block->iface_block_device, configuration);
 }
 
 static void
index 3a4f5be..60da384 100644 (file)
@@ -93,6 +93,14 @@ static void fstab_monitor_on_entry_removed (UDisksFstabMonitor *monitor,
                                             UDisksFstabEntry   *entry,
                                             gpointer            user_data);
 
+static void crypttab_monitor_on_entry_added (UDisksCrypttabMonitor *monitor,
+                                             UDisksCrypttabEntry   *entry,
+                                             gpointer               user_data);
+
+static void crypttab_monitor_on_entry_removed (UDisksCrypttabMonitor *monitor,
+                                               UDisksCrypttabEntry   *entry,
+                                               gpointer               user_data);
+
 G_DEFINE_TYPE (UDisksLinuxProvider, udisks_linux_provider, UDISKS_TYPE_PROVIDER);
 
 static void
@@ -120,6 +128,12 @@ udisks_linux_provider_finalize (GObject *object)
   g_signal_handlers_disconnect_by_func (udisks_daemon_get_fstab_monitor (daemon),
                                         G_CALLBACK (fstab_monitor_on_entry_removed),
                                         provider);
+  g_signal_handlers_disconnect_by_func (udisks_daemon_get_crypttab_monitor (daemon),
+                                        G_CALLBACK (crypttab_monitor_on_entry_added),
+                                        provider);
+  g_signal_handlers_disconnect_by_func (udisks_daemon_get_crypttab_monitor (daemon),
+                                        G_CALLBACK (crypttab_monitor_on_entry_removed),
+                                        provider);
 
   if (G_OBJECT_CLASS (udisks_linux_provider_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (udisks_linux_provider_parent_class)->finalize (object);
@@ -201,7 +215,7 @@ udisks_linux_provider_start (UDisksProvider *_provider)
 
   provider->coldplug = FALSE;
 
-  /* update BlockDevice:FstabEntries whenever fstab entries are added or removed */
+  /* update BlockDevice:Configuration whenever fstab or crypttab entries are added or removed */
   g_signal_connect (udisks_daemon_get_fstab_monitor (daemon),
                     "entry-added",
                     G_CALLBACK (fstab_monitor_on_entry_added),
@@ -210,6 +224,14 @@ udisks_linux_provider_start (UDisksProvider *_provider)
                     "entry-removed",
                     G_CALLBACK (fstab_monitor_on_entry_removed),
                     provider);
+  g_signal_connect (udisks_daemon_get_crypttab_monitor (daemon),
+                    "entry-added",
+                    G_CALLBACK (crypttab_monitor_on_entry_added),
+                    provider);
+  g_signal_connect (udisks_daemon_get_crypttab_monitor (daemon),
+                    "entry-removed",
+                    G_CALLBACK (crypttab_monitor_on_entry_removed),
+                    provider);
 }
 
 
@@ -586,3 +608,21 @@ fstab_monitor_on_entry_removed (UDisksFstabMonitor *monitor,
   UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
   update_all_block_devices (provider);
 }
+
+static void
+crypttab_monitor_on_entry_added (UDisksCrypttabMonitor *monitor,
+                                 UDisksCrypttabEntry   *entry,
+                                 gpointer               user_data)
+{
+  UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
+  update_all_block_devices (provider);
+}
+
+static void
+crypttab_monitor_on_entry_removed (UDisksCrypttabMonitor *monitor,
+                                   UDisksCrypttabEntry   *entry,
+                                   gpointer               user_data)
+{
+  UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
+  update_all_block_devices (provider);
+}
index 3cc2bf8..5dfd77e 100644 (file)
@@ -22,6 +22,7 @@
 #define __UDISKS_PRIVATE_H__
 
 #include "udisksdaemontypes.h"
+#include <mntent.h>
 
 G_BEGIN_DECLS
 
@@ -31,6 +32,11 @@ UDisksMount *_udisks_mount_new (dev_t dev,
 
 UDisksFstabEntry *_udisks_fstab_entry_new (const struct mntent *mntent);
 
+UDisksCrypttabEntry *_udisks_crypttab_entry_new (const gchar *name,
+                                                 const gchar *device,
+                                                 const gchar *passphrase,
+                                                 const gchar *options);
+
 G_END_DECLS
 
 #endif /* __UDISKS_PRIVATE_H__ */