g13: Implement --umount for dm-crypt.
[gnupg.git] / g13 / mount.c
index a9203d1..f4371cc 100644 (file)
 
 #include "keyblob.h"
 #include "backend.h"
-#include "utils.h"
-#include "../common/sysutils.h"
-#include "call-gpg.h"
+#include "g13tuple.h"
 #include "mountinfo.h"
 #include "runner.h"
-
-
-/* Parse the header prefix and return the length of the entire header.  */
-static gpg_error_t
-parse_header (const char *filename,
-              const unsigned char *packet, size_t packetlen,
-              size_t *r_headerlen)
-{
-  unsigned int len;
-
-  if (packetlen != 32)
-    return gpg_error (GPG_ERR_BUG);
-
-  len = ((packet[2] << 24) | (packet[3] << 16)
-         | (packet[4] << 8) | packet[5]);
-  if (packet[0] != (0xc0|61) || len < 26
-      || memcmp (packet+6, "GnuPG/G13", 10))
-    {
-      log_error ("file '%s' is not valid container\n", filename);
-      return gpg_error (GPG_ERR_INV_OBJ);
-    }
-  if (packet[16] != 1)
-    {
-      log_error ("unknown version %u of container '%s'\n",
-                 (unsigned int)packet[16], filename);
-      return gpg_error (GPG_ERR_INV_OBJ);
-    }
-  if (packet[17] || packet[18]
-      || packet[26] || packet[27] || packet[28] || packet[29]
-      || packet[30] || packet[31])
-    log_info ("WARNING: unknown meta information in '%s'\n", filename);
-  if (packet[19])
-    log_info ("WARNING: OS flag is not supported in '%s'\n", filename);
-  if (packet[24] != 1 || packet[25] != 0)
-    {
-      log_error ("meta data copies in '%s' are not supported\n", filename);
-      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-    }
-
-  len = ((packet[20] << 24) | (packet[21] << 16)
-         | (packet[22] << 8) | packet[23]);
-
-  /* Do a basic sanity check on the length.  */
-  if (len < 32 || len > 1024*1024)
-    {
-      log_error ("bad length given in container '%s'\n", filename);
-      return gpg_error (GPG_ERR_INV_OBJ);
-    }
-
-  *r_headerlen = len;
-  return 0;
-}
-
-
-/* Read the prefix of the keyblob and do some basic parsing.  On
-   success returns an open estream file at R_FP and the length of the
-   header at R_HEADERLEN.  */
-static gpg_error_t
-read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
-{
-  gpg_error_t err;
-  estream_t fp;
-  unsigned char packet[32];
-
-  *r_fp = NULL;
-
-  fp = es_fopen (filename, "rb");
-  if (!fp)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error reading '%s': %s\n", filename, gpg_strerror (err));
-      return err;
-    }
-
-  /* Read the header.  It is defined as 32 bytes thus we read it in one go.  */
-  if (es_fread (packet, 32, 1, fp) != 1)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error reading the header of '%s': %s\n",
-                 filename, gpg_strerror (err));
-      es_fclose (fp);
-      return err;
-    }
-
-  err = parse_header (filename, packet, 32, r_headerlen);
-  if (err)
-    es_fclose (fp);
-  else
-    *r_fp = fp;
-
-  return err;
-}
-
-
-/* Read the keyblob at FILENAME.  The caller should have acquired a
-   lockfile and checked that the file exists.  */
-static gpg_error_t
-read_keyblob (const char *filename,
-              void **r_enckeyblob, size_t *r_enckeybloblen)
-{
-  gpg_error_t err;
-  estream_t fp = NULL;
-  size_t headerlen = 0;
-  size_t msglen;
-  void *msg = NULL;
-
-  *r_enckeyblob = NULL;
-  *r_enckeybloblen = 0;
-
-  err = read_keyblob_prefix (filename, &fp, &headerlen);
-  if (err)
-    goto leave;
-
-  if (opt.verbose)
-    log_info ("header length of '%s' is %zu\n", filename, headerlen);
-
-  /* Read everything including the padding.  We should eventually do a
-     regular OpenPGP parsing to detect the padding packet and pass
-     only the actual used OpenPGP data to the engine.  This is in
-     particular required when supporting CMS which will be
-     encapsulated in an OpenPGP packet.  */
-  assert (headerlen >= 32);
-  msglen = headerlen - 32;
-  if (!msglen)
-    {
-      err = gpg_error (GPG_ERR_NO_DATA);
-      goto leave;
-    }
-  msg = xtrymalloc (msglen);
-  if (!msglen)
-    {
-      err = gpg_error_from_syserror ();
-      goto leave;
-    }
-  if (es_fread (msg, msglen, 1, fp) != 1)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error reading keyblob of '%s': %s\n",
-                 filename, gpg_strerror (err));
-      goto leave;
-    }
-
-  *r_enckeyblob = msg;
-  msg = NULL;
-  *r_enckeybloblen = msglen;
-
- leave:
-  xfree (msg);
-  es_fclose (fp);
-
-  return err;
-}
-
-
-
-
-/* Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result at
-   (R_KEYBLOB, R_KEYBLOBLEN).  Returns 0 on success or an error code.
-   On error R_KEYBLOB is set to NULL.  */
-static gpg_error_t
-decrypt_keyblob (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
-                 void **r_keyblob, size_t *r_keybloblen)
-{
-  gpg_error_t err;
-
-  /* FIXME:  For now we only implement OpenPGP.  */
-  err = gpg_decrypt_blob (ctrl, enckeyblob, enckeybloblen,
-                          r_keyblob, r_keybloblen);
-
-  return err;
-}
-
-
-static void
-dump_keyblob (tupledesc_t tuples)
-{
-  size_t n;
-  unsigned int tag;
-  const void *value;
-
-  log_info ("keyblob dump:\n");
-  tag = KEYBLOB_TAG_BLOBVERSION;
-  value = find_tuple (tuples, tag, &n);
-  while (value)
-    {
-      log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
-      if (tag == KEYBLOB_TAG_ENCKEY
-          ||  tag == KEYBLOB_TAG_MACKEY)
-        log_printf ("[confidential]\n");
-      else if (!n)
-        log_printf ("[none]\n");
-      else
-        log_printhex ("", value, n);
-      value = next_tuple (tuples, &tag, &n);
-    }
-}
-
+#include "host2net.h"
+#include "server.h"  /*(g13_keyblob_decrypt)*/
+#include "../common/sysutils.h"
+#include "call-syshelp.h"
 
 
 /* Mount the container with name FILENAME at MOUNTPOINT.  */
@@ -242,6 +47,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
 {
   gpg_error_t err;
   dotlock_t lock;
+  int needs_syshelp = 0;
   void *enckeyblob = NULL;
   size_t enckeybloblen;
   void *keyblob = NULL;
@@ -252,11 +58,26 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
   int conttype;
   unsigned int rid;
   char *mountpoint_buffer = NULL;
+  char *blockdev_buffer = NULL;
 
   /* A quick check to see whether the container exists.  */
-  if (access (filename, R_OK))
+  if (access (filename, F_OK))
     return gpg_error_from_syserror ();
 
+  /* Decide whether we need to use the g13-syshelp.  */
+  err = call_syshelp_find_device (ctrl, filename, &blockdev_buffer);
+  if (!err)
+    {
+      needs_syshelp = 1;
+      filename = blockdev_buffer;
+    }
+  else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
+    {
+      log_error ("error finding device '%s': %s <%s>\n",
+                 filename, gpg_strerror (err), gpg_strsource (err));
+      return err;
+    }
+
   if (!mountpoint)
     {
       mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
@@ -273,41 +94,54 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
       mountpoint = mountpoint_buffer;
     }
 
-  /* Try to take a lock.  */
-  lock = dotlock_create (filename, 0);
-  if (!lock)
+  err = 0;
+  if (needs_syshelp)
+    lock = NULL;
+  else
     {
-      xfree (mountpoint_buffer);
-      return gpg_error_from_syserror ();
-    }
+      /* Try to take a lock.  */
+      lock = dotlock_create (filename, 0);
+      if (!lock)
+        {
+          xfree (mountpoint_buffer);
+          return gpg_error_from_syserror ();
+        }
 
-  if (dotlock_take (lock, 0))
-    {
-      err = gpg_error_from_syserror ();
-      goto leave;
+      if (dotlock_take (lock, 0))
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
     }
-  else
-    err = 0;
 
   /* Check again that the file exists.  */
-  {
-    struct stat sb;
+  if (!needs_syshelp)
+    {
+      struct stat sb;
 
-    if (stat (filename, &sb))
-      {
-        err = gpg_error_from_syserror ();
-        goto leave;
-      }
-  }
+      if (stat (filename, &sb))
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
 
   /* Read the encrypted keyblob.  */
-  err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
+  if (needs_syshelp)
+    {
+      err = call_syshelp_set_device (ctrl, filename);
+      if (err)
+        goto leave;
+      err = call_syshelp_get_keyblob (ctrl, &enckeyblob, &enckeybloblen);
+    }
+  else
+    err = g13_keyblob_read (filename, &enckeyblob, &enckeybloblen);
   if (err)
     goto leave;
 
   /* Decrypt that keyblob and store it in a tuple descriptor.  */
-  err = decrypt_keyblob (ctrl, enckeyblob, enckeybloblen,
-                         &keyblob, &keybloblen);
+  err = g13_keyblob_decrypt (ctrl, enckeyblob, enckeybloblen,
+                             &keyblob, &keybloblen);
   if (err)
     goto leave;
   xfree (enckeyblob);
@@ -323,7 +157,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
       goto leave;
     }
   if (opt.verbose)
-    dump_keyblob (tuples);
+    dump_tupledesc (tuples);
 
   value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
   if (!value || n != 2)
@@ -337,8 +171,15 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
       goto leave;
     }
   err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
-  if (!err)
+  if (err)
+    ;
+  else if (conttype == CONTTYPE_DM_CRYPT)
+    g13_request_shutdown ();
+  else
     {
+      /* Unless this is a DM-CRYPT mount we put it into our mounttable
+         so that we can manage the mounts ourselves.  For dm-crypt we
+         do not keep a process to monitor he mounts (for now).  */
       err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
                                  !!mountpoint_buffer);
       /* Fixme: What shall we do if this fails?  Add a provisional
@@ -362,6 +203,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
   xfree (enckeyblob);
   dotlock_destroy (lock);
   xfree (mountpoint_buffer);
+  xfree (blockdev_buffer);
   return err;
 }
 
@@ -372,46 +214,50 @@ gpg_error_t
 g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
 {
   gpg_error_t err;
-  unsigned int rid;
-  runner_t runner;
-
-  (void)ctrl;
+  char *blockdev;
 
   if (!filename && !mountpoint)
     return gpg_error (GPG_ERR_ENOENT);
-  err = mountinfo_find_mount (filename, mountpoint, &rid);
-  if (err)
-    return err;
 
-  runner = runner_find_by_rid (rid);
-  if (!runner)
+  /* Decide whether we need to use the g13-syshelp.  */
+  err = call_syshelp_find_device (ctrl, filename, &blockdev);
+  if (!err)
     {
-      log_error ("runner %u not found\n", rid);
-      return gpg_error (GPG_ERR_NOT_FOUND);
+      /* Need to employ the syshelper to umount the file system.  */
+      /* FIXME: We should get the CONTTYPE from the blockdev.  */
+      err = be_umount_container (ctrl, CONTTYPE_DM_CRYPT, blockdev);
+      if (!err)
+        {
+          /* if (conttype == CONTTYPE_DM_CRYPT) */
+          g13_request_shutdown ();
+        }
     }
+  else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
+    {
+      log_error ("error finding device '%s': %s <%s>\n",
+                 filename, gpg_strerror (err), gpg_strsource (err));
+    }
+  else
+    {
+      /* Not in g13tab - kill the runner process for this mount.  */
+      unsigned int rid;
+      runner_t runner;
 
-  runner_cancel (runner);
-  runner_release (runner);
-
-  return 0;
-}
-
+      err = mountinfo_find_mount (filename, mountpoint, &rid);
+      if (err)
+        return err;
 
-/* Test whether the container with name FILENAME is a suitable G13
-   container.  This function may even be called on a mounted
-   container.  */
-gpg_error_t
-g13_is_container (ctrl_t ctrl, const char *filename)
-{
-  gpg_error_t err;
-  estream_t fp = NULL;
-  size_t dummy;
+      runner = runner_find_by_rid (rid);
+      if (!runner)
+        {
+          log_error ("runner %u not found\n", rid);
+          return gpg_error (GPG_ERR_NOT_FOUND);
+        }
 
-  (void)ctrl;
+      runner_cancel (runner);
+      runner_release (runner);
+    }
 
-  /* Read just the prefix of the header.  */
-  err = read_keyblob_prefix (filename, &fp, &dummy);
-  if (!err)
-    es_fclose (fp);
+  xfree (blockdev);
   return err;
 }