f4371cce5dca96d3997e5b76c9aedf73770b8ef7
[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 "server.h"  /*(g13_keyblob_decrypt)*/
40 #include "../common/sysutils.h"
41 #include "call-syshelp.h"
42
43
44 /* Mount the container with name FILENAME at MOUNTPOINT.  */
45 gpg_error_t
46 g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
47 {
48   gpg_error_t err;
49   dotlock_t lock;
50   int needs_syshelp = 0;
51   void *enckeyblob = NULL;
52   size_t enckeybloblen;
53   void *keyblob = NULL;
54   size_t keybloblen;
55   tupledesc_t tuples = NULL;
56   size_t n;
57   const unsigned char *value;
58   int conttype;
59   unsigned int rid;
60   char *mountpoint_buffer = NULL;
61   char *blockdev_buffer = NULL;
62
63   /* A quick check to see whether the container exists.  */
64   if (access (filename, F_OK))
65     return gpg_error_from_syserror ();
66
67   /* Decide whether we need to use the g13-syshelp.  */
68   err = call_syshelp_find_device (ctrl, filename, &blockdev_buffer);
69   if (!err)
70     {
71       needs_syshelp = 1;
72       filename = blockdev_buffer;
73     }
74   else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
75     {
76       log_error ("error finding device '%s': %s <%s>\n",
77                  filename, gpg_strerror (err), gpg_strsource (err));
78       return err;
79     }
80
81   if (!mountpoint)
82     {
83       mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
84       if (!mountpoint_buffer)
85         return gpg_error_from_syserror ();
86       if (!gnupg_mkdtemp (mountpoint_buffer))
87         {
88           err = gpg_error_from_syserror ();
89           log_error (_("can't create directory '%s': %s\n"),
90                      "/tmp/g13-XXXXXX", gpg_strerror (err));
91           xfree (mountpoint_buffer);
92           return err;
93         }
94       mountpoint = mountpoint_buffer;
95     }
96
97   err = 0;
98   if (needs_syshelp)
99     lock = NULL;
100   else
101     {
102       /* Try to take a lock.  */
103       lock = dotlock_create (filename, 0);
104       if (!lock)
105         {
106           xfree (mountpoint_buffer);
107           return gpg_error_from_syserror ();
108         }
109
110       if (dotlock_take (lock, 0))
111         {
112           err = gpg_error_from_syserror ();
113           goto leave;
114         }
115     }
116
117   /* Check again that the file exists.  */
118   if (!needs_syshelp)
119     {
120       struct stat sb;
121
122       if (stat (filename, &sb))
123         {
124           err = gpg_error_from_syserror ();
125           goto leave;
126         }
127     }
128
129   /* Read the encrypted keyblob.  */
130   if (needs_syshelp)
131     {
132       err = call_syshelp_set_device (ctrl, filename);
133       if (err)
134         goto leave;
135       err = call_syshelp_get_keyblob (ctrl, &enckeyblob, &enckeybloblen);
136     }
137   else
138     err = g13_keyblob_read (filename, &enckeyblob, &enckeybloblen);
139   if (err)
140     goto leave;
141
142   /* Decrypt that keyblob and store it in a tuple descriptor.  */
143   err = g13_keyblob_decrypt (ctrl, enckeyblob, enckeybloblen,
144                              &keyblob, &keybloblen);
145   if (err)
146     goto leave;
147   xfree (enckeyblob);
148   enckeyblob = NULL;
149
150   err = create_tupledesc (&tuples, keyblob, keybloblen);
151   if (!err)
152     keyblob = NULL;
153   else
154     {
155       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
156         log_error ("unknown keyblob version\n");
157       goto leave;
158     }
159   if (opt.verbose)
160     dump_tupledesc (tuples);
161
162   value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
163   if (!value || n != 2)
164     conttype = 0;
165   else
166     conttype = (value[0] << 8 | value[1]);
167   if (!be_is_supported_conttype (conttype))
168     {
169       log_error ("content type %d is not supported\n", conttype);
170       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
171       goto leave;
172     }
173   err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
174   if (err)
175     ;
176   else if (conttype == CONTTYPE_DM_CRYPT)
177     g13_request_shutdown ();
178   else
179     {
180       /* Unless this is a DM-CRYPT mount we put it into our mounttable
181          so that we can manage the mounts ourselves.  For dm-crypt we
182          do not keep a process to monitor he mounts (for now).  */
183       err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
184                                  !!mountpoint_buffer);
185       /* Fixme: What shall we do if this fails?  Add a provisional
186          mountinfo entry first and remove it on error? */
187       if (!err)
188         {
189           char *tmp = percent_plus_escape (mountpoint);
190           if (!tmp)
191             err = gpg_error_from_syserror ();
192           else
193             {
194               g13_status (ctrl, STATUS_MOUNTPOINT, tmp, NULL);
195               xfree (tmp);
196             }
197         }
198     }
199
200  leave:
201   destroy_tupledesc (tuples);
202   xfree (keyblob);
203   xfree (enckeyblob);
204   dotlock_destroy (lock);
205   xfree (mountpoint_buffer);
206   xfree (blockdev_buffer);
207   return err;
208 }
209
210
211 /* Unmount the container with name FILENAME or the one mounted at
212    MOUNTPOINT.  If both are given the FILENAME takes precedence.  */
213 gpg_error_t
214 g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
215 {
216   gpg_error_t err;
217   char *blockdev;
218
219   if (!filename && !mountpoint)
220     return gpg_error (GPG_ERR_ENOENT);
221
222   /* Decide whether we need to use the g13-syshelp.  */
223   err = call_syshelp_find_device (ctrl, filename, &blockdev);
224   if (!err)
225     {
226       /* Need to employ the syshelper to umount the file system.  */
227       /* FIXME: We should get the CONTTYPE from the blockdev.  */
228       err = be_umount_container (ctrl, CONTTYPE_DM_CRYPT, blockdev);
229       if (!err)
230         {
231           /* if (conttype == CONTTYPE_DM_CRYPT) */
232           g13_request_shutdown ();
233         }
234     }
235   else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
236     {
237       log_error ("error finding device '%s': %s <%s>\n",
238                  filename, gpg_strerror (err), gpg_strsource (err));
239     }
240   else
241     {
242       /* Not in g13tab - kill the runner process for this mount.  */
243       unsigned int rid;
244       runner_t runner;
245
246       err = mountinfo_find_mount (filename, mountpoint, &rid);
247       if (err)
248         return err;
249
250       runner = runner_find_by_rid (rid);
251       if (!runner)
252         {
253           log_error ("runner %u not found\n", rid);
254           return gpg_error (GPG_ERR_NOT_FOUND);
255         }
256
257       runner_cancel (runner);
258       runner_release (runner);
259     }
260
261   xfree (blockdev);
262   return err;
263 }