272cd77e0e3a519bbaf967970833e3bb9cda3655
[gnupg.git] / g13 / mount.c
1 /* mount.c - Mount a crypto container
2  * Copyright (C) 2009 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <assert.h>
28
29 #include "g13.h"
30 #include "i18n.h"
31 #include "mount.h"
32
33 #include "keyblob.h"
34 #include "backend.h"
35 #include "g13tuple.h"
36 #include "mountinfo.h"
37 #include "runner.h"
38 #include "host2net.h"
39 #include "../common/sysutils.h"
40
41
42 /* Mount the container with name FILENAME at MOUNTPOINT.  */
43 gpg_error_t
44 g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
45 {
46   gpg_error_t err;
47   dotlock_t lock;
48   int needs_syshelp;
49   void *enckeyblob = NULL;
50   size_t enckeybloblen;
51   void *keyblob = NULL;
52   size_t keybloblen;
53   tupledesc_t tuples = NULL;
54   size_t n;
55   const unsigned char *value;
56   int conttype;
57   unsigned int rid;
58   char *mountpoint_buffer = NULL;
59
60   /* A quick check to see whether the container exists.  */
61   if (access (filename, R_OK))
62     return gpg_error_from_syserror ();
63
64   /* Decide whether we need to use the g13-syshelp because we can't
65      use lock files for them.  This is most likely the case for device
66      files; thus we test for this.  FIXME: The correct solution would
67      be to call g13-syshelp to match the file against the g13tab.  */
68   needs_syshelp = !strncmp (filename, "/dev/", 5);
69
70   if (!mountpoint)
71     {
72       mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
73       if (!mountpoint_buffer)
74         return gpg_error_from_syserror ();
75       if (!gnupg_mkdtemp (mountpoint_buffer))
76         {
77           err = gpg_error_from_syserror ();
78           log_error (_("can't create directory '%s': %s\n"),
79                      "/tmp/g13-XXXXXX", gpg_strerror (err));
80           xfree (mountpoint_buffer);
81           return err;
82         }
83       mountpoint = mountpoint_buffer;
84     }
85
86   err = 0;
87   if (needs_syshelp)
88     lock = NULL;
89   else
90     {
91       /* Try to take a lock.  */
92       lock = dotlock_create (filename, 0);
93       if (!lock)
94         {
95           xfree (mountpoint_buffer);
96           return gpg_error_from_syserror ();
97         }
98
99       if (dotlock_take (lock, 0))
100         {
101           err = gpg_error_from_syserror ();
102           goto leave;
103         }
104     }
105
106   /* Check again that the file exists.  */
107   {
108     struct stat sb;
109
110     if (stat (filename, &sb))
111       {
112         err = gpg_error_from_syserror ();
113         goto leave;
114       }
115   }
116
117   /* Read the encrypted keyblob.  */
118   /* Fixme: Should we move this to syshelp for dm-crypt or do we
119      assume that the encrypted device is world readable?  */
120   err = g13_keyblob_read (filename, &enckeyblob, &enckeybloblen);
121   if (err)
122     goto leave;
123
124   /* Decrypt that keyblob and store it in a tuple descriptor.  */
125   err = g13_keyblob_decrypt (ctrl, enckeyblob, enckeybloblen,
126                              &keyblob, &keybloblen);
127   if (err)
128     goto leave;
129   xfree (enckeyblob);
130   enckeyblob = NULL;
131
132   err = create_tupledesc (&tuples, keyblob, keybloblen);
133   if (!err)
134     keyblob = NULL;
135   else
136     {
137       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
138         log_error ("unknown keyblob version\n");
139       goto leave;
140     }
141   if (opt.verbose)
142     dump_tupledesc (tuples);
143
144   value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
145   if (!value || n != 2)
146     conttype = 0;
147   else
148     conttype = (value[0] << 8 | value[1]);
149   if (!be_is_supported_conttype (conttype))
150     {
151       log_error ("content type %d is not supported\n", conttype);
152       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
153       goto leave;
154     }
155   err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
156   if (err)
157     ;
158   else if (conttype == CONTTYPE_DM_CRYPT)
159     g13_request_shutdown ();
160   else
161     {
162       /* Unless this is a DM-CRYPT mount we put it into our mounttable
163          so that we can manage the mounts ourselves.  For dm-crypt we
164          do not keep a process to monitor he mounts (for now).  */
165       err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
166                                  !!mountpoint_buffer);
167       /* Fixme: What shall we do if this fails?  Add a provisional
168          mountinfo entry first and remove it on error? */
169       if (!err)
170         {
171           char *tmp = percent_plus_escape (mountpoint);
172           if (!tmp)
173             err = gpg_error_from_syserror ();
174           else
175             {
176               g13_status (ctrl, STATUS_MOUNTPOINT, tmp, NULL);
177               xfree (tmp);
178             }
179         }
180     }
181
182  leave:
183   destroy_tupledesc (tuples);
184   xfree (keyblob);
185   xfree (enckeyblob);
186   dotlock_destroy (lock);
187   xfree (mountpoint_buffer);
188   return err;
189 }
190
191
192 /* Unmount the container with name FILENAME or the one mounted at
193    MOUNTPOINT.  If both are given the FILENAME takes precedence.  */
194 gpg_error_t
195 g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
196 {
197   gpg_error_t err;
198   unsigned int rid;
199   runner_t runner;
200
201   (void)ctrl;
202
203   if (!filename && !mountpoint)
204     return gpg_error (GPG_ERR_ENOENT);
205   err = mountinfo_find_mount (filename, mountpoint, &rid);
206   if (err)
207     return err;
208
209   runner = runner_find_by_rid (rid);
210   if (!runner)
211     {
212       log_error ("runner %u not found\n", rid);
213       return gpg_error (GPG_ERR_NOT_FOUND);
214     }
215
216   runner_cancel (runner);
217   runner_release (runner);
218
219   return 0;
220 }