a9203d11f234900c20ddfe4e02f8cf586ab9c482
[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 "utils.h"
36 #include "../common/sysutils.h"
37 #include "call-gpg.h"
38 #include "mountinfo.h"
39 #include "runner.h"
40
41
42 /* Parse the header prefix and return the length of the entire header.  */
43 static gpg_error_t
44 parse_header (const char *filename,
45               const unsigned char *packet, size_t packetlen,
46               size_t *r_headerlen)
47 {
48   unsigned int len;
49
50   if (packetlen != 32)
51     return gpg_error (GPG_ERR_BUG);
52
53   len = ((packet[2] << 24) | (packet[3] << 16)
54          | (packet[4] << 8) | packet[5]);
55   if (packet[0] != (0xc0|61) || len < 26
56       || memcmp (packet+6, "GnuPG/G13", 10))
57     {
58       log_error ("file '%s' is not valid container\n", filename);
59       return gpg_error (GPG_ERR_INV_OBJ);
60     }
61   if (packet[16] != 1)
62     {
63       log_error ("unknown version %u of container '%s'\n",
64                  (unsigned int)packet[16], filename);
65       return gpg_error (GPG_ERR_INV_OBJ);
66     }
67   if (packet[17] || packet[18]
68       || packet[26] || packet[27] || packet[28] || packet[29]
69       || packet[30] || packet[31])
70     log_info ("WARNING: unknown meta information in '%s'\n", filename);
71   if (packet[19])
72     log_info ("WARNING: OS flag is not supported in '%s'\n", filename);
73   if (packet[24] != 1 || packet[25] != 0)
74     {
75       log_error ("meta data copies in '%s' are not supported\n", filename);
76       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
77     }
78
79   len = ((packet[20] << 24) | (packet[21] << 16)
80          | (packet[22] << 8) | packet[23]);
81
82   /* Do a basic sanity check on the length.  */
83   if (len < 32 || len > 1024*1024)
84     {
85       log_error ("bad length given in container '%s'\n", filename);
86       return gpg_error (GPG_ERR_INV_OBJ);
87     }
88
89   *r_headerlen = len;
90   return 0;
91 }
92
93
94 /* Read the prefix of the keyblob and do some basic parsing.  On
95    success returns an open estream file at R_FP and the length of the
96    header at R_HEADERLEN.  */
97 static gpg_error_t
98 read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
99 {
100   gpg_error_t err;
101   estream_t fp;
102   unsigned char packet[32];
103
104   *r_fp = NULL;
105
106   fp = es_fopen (filename, "rb");
107   if (!fp)
108     {
109       err = gpg_error_from_syserror ();
110       log_error ("error reading '%s': %s\n", filename, gpg_strerror (err));
111       return err;
112     }
113
114   /* Read the header.  It is defined as 32 bytes thus we read it in one go.  */
115   if (es_fread (packet, 32, 1, fp) != 1)
116     {
117       err = gpg_error_from_syserror ();
118       log_error ("error reading the header of '%s': %s\n",
119                  filename, gpg_strerror (err));
120       es_fclose (fp);
121       return err;
122     }
123
124   err = parse_header (filename, packet, 32, r_headerlen);
125   if (err)
126     es_fclose (fp);
127   else
128     *r_fp = fp;
129
130   return err;
131 }
132
133
134 /* Read the keyblob at FILENAME.  The caller should have acquired a
135    lockfile and checked that the file exists.  */
136 static gpg_error_t
137 read_keyblob (const char *filename,
138               void **r_enckeyblob, size_t *r_enckeybloblen)
139 {
140   gpg_error_t err;
141   estream_t fp = NULL;
142   size_t headerlen = 0;
143   size_t msglen;
144   void *msg = NULL;
145
146   *r_enckeyblob = NULL;
147   *r_enckeybloblen = 0;
148
149   err = read_keyblob_prefix (filename, &fp, &headerlen);
150   if (err)
151     goto leave;
152
153   if (opt.verbose)
154     log_info ("header length of '%s' is %zu\n", filename, headerlen);
155
156   /* Read everything including the padding.  We should eventually do a
157      regular OpenPGP parsing to detect the padding packet and pass
158      only the actual used OpenPGP data to the engine.  This is in
159      particular required when supporting CMS which will be
160      encapsulated in an OpenPGP packet.  */
161   assert (headerlen >= 32);
162   msglen = headerlen - 32;
163   if (!msglen)
164     {
165       err = gpg_error (GPG_ERR_NO_DATA);
166       goto leave;
167     }
168   msg = xtrymalloc (msglen);
169   if (!msglen)
170     {
171       err = gpg_error_from_syserror ();
172       goto leave;
173     }
174   if (es_fread (msg, msglen, 1, fp) != 1)
175     {
176       err = gpg_error_from_syserror ();
177       log_error ("error reading keyblob of '%s': %s\n",
178                  filename, gpg_strerror (err));
179       goto leave;
180     }
181
182   *r_enckeyblob = msg;
183   msg = NULL;
184   *r_enckeybloblen = msglen;
185
186  leave:
187   xfree (msg);
188   es_fclose (fp);
189
190   return err;
191 }
192
193
194
195
196 /* Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result at
197    (R_KEYBLOB, R_KEYBLOBLEN).  Returns 0 on success or an error code.
198    On error R_KEYBLOB is set to NULL.  */
199 static gpg_error_t
200 decrypt_keyblob (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
201                  void **r_keyblob, size_t *r_keybloblen)
202 {
203   gpg_error_t err;
204
205   /* FIXME:  For now we only implement OpenPGP.  */
206   err = gpg_decrypt_blob (ctrl, enckeyblob, enckeybloblen,
207                           r_keyblob, r_keybloblen);
208
209   return err;
210 }
211
212
213 static void
214 dump_keyblob (tupledesc_t tuples)
215 {
216   size_t n;
217   unsigned int tag;
218   const void *value;
219
220   log_info ("keyblob dump:\n");
221   tag = KEYBLOB_TAG_BLOBVERSION;
222   value = find_tuple (tuples, tag, &n);
223   while (value)
224     {
225       log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
226       if (tag == KEYBLOB_TAG_ENCKEY
227           ||  tag == KEYBLOB_TAG_MACKEY)
228         log_printf ("[confidential]\n");
229       else if (!n)
230         log_printf ("[none]\n");
231       else
232         log_printhex ("", value, n);
233       value = next_tuple (tuples, &tag, &n);
234     }
235 }
236
237
238
239 /* Mount the container with name FILENAME at MOUNTPOINT.  */
240 gpg_error_t
241 g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
242 {
243   gpg_error_t err;
244   dotlock_t lock;
245   void *enckeyblob = NULL;
246   size_t enckeybloblen;
247   void *keyblob = NULL;
248   size_t keybloblen;
249   tupledesc_t tuples = NULL;
250   size_t n;
251   const unsigned char *value;
252   int conttype;
253   unsigned int rid;
254   char *mountpoint_buffer = NULL;
255
256   /* A quick check to see whether the container exists.  */
257   if (access (filename, R_OK))
258     return gpg_error_from_syserror ();
259
260   if (!mountpoint)
261     {
262       mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
263       if (!mountpoint_buffer)
264         return gpg_error_from_syserror ();
265       if (!gnupg_mkdtemp (mountpoint_buffer))
266         {
267           err = gpg_error_from_syserror ();
268           log_error (_("can't create directory '%s': %s\n"),
269                      "/tmp/g13-XXXXXX", gpg_strerror (err));
270           xfree (mountpoint_buffer);
271           return err;
272         }
273       mountpoint = mountpoint_buffer;
274     }
275
276   /* Try to take a lock.  */
277   lock = dotlock_create (filename, 0);
278   if (!lock)
279     {
280       xfree (mountpoint_buffer);
281       return gpg_error_from_syserror ();
282     }
283
284   if (dotlock_take (lock, 0))
285     {
286       err = gpg_error_from_syserror ();
287       goto leave;
288     }
289   else
290     err = 0;
291
292   /* Check again that the file exists.  */
293   {
294     struct stat sb;
295
296     if (stat (filename, &sb))
297       {
298         err = gpg_error_from_syserror ();
299         goto leave;
300       }
301   }
302
303   /* Read the encrypted keyblob.  */
304   err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
305   if (err)
306     goto leave;
307
308   /* Decrypt that keyblob and store it in a tuple descriptor.  */
309   err = decrypt_keyblob (ctrl, enckeyblob, enckeybloblen,
310                          &keyblob, &keybloblen);
311   if (err)
312     goto leave;
313   xfree (enckeyblob);
314   enckeyblob = NULL;
315
316   err = create_tupledesc (&tuples, keyblob, keybloblen);
317   if (!err)
318     keyblob = NULL;
319   else
320     {
321       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
322         log_error ("unknown keyblob version\n");
323       goto leave;
324     }
325   if (opt.verbose)
326     dump_keyblob (tuples);
327
328   value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
329   if (!value || n != 2)
330     conttype = 0;
331   else
332     conttype = (value[0] << 8 | value[1]);
333   if (!be_is_supported_conttype (conttype))
334     {
335       log_error ("content type %d is not supported\n", conttype);
336       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
337       goto leave;
338     }
339   err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
340   if (!err)
341     {
342       err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
343                                  !!mountpoint_buffer);
344       /* Fixme: What shall we do if this fails?  Add a provisional
345          mountinfo entry first and remove it on error? */
346       if (!err)
347         {
348           char *tmp = percent_plus_escape (mountpoint);
349           if (!tmp)
350             err = gpg_error_from_syserror ();
351           else
352             {
353               g13_status (ctrl, STATUS_MOUNTPOINT, tmp, NULL);
354               xfree (tmp);
355             }
356         }
357     }
358
359  leave:
360   destroy_tupledesc (tuples);
361   xfree (keyblob);
362   xfree (enckeyblob);
363   dotlock_destroy (lock);
364   xfree (mountpoint_buffer);
365   return err;
366 }
367
368
369 /* Unmount the container with name FILENAME or the one mounted at
370    MOUNTPOINT.  If both are given the FILENAME takes precedence.  */
371 gpg_error_t
372 g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
373 {
374   gpg_error_t err;
375   unsigned int rid;
376   runner_t runner;
377
378   (void)ctrl;
379
380   if (!filename && !mountpoint)
381     return gpg_error (GPG_ERR_ENOENT);
382   err = mountinfo_find_mount (filename, mountpoint, &rid);
383   if (err)
384     return err;
385
386   runner = runner_find_by_rid (rid);
387   if (!runner)
388     {
389       log_error ("runner %u not found\n", rid);
390       return gpg_error (GPG_ERR_NOT_FOUND);
391     }
392
393   runner_cancel (runner);
394   runner_release (runner);
395
396   return 0;
397 }
398
399
400 /* Test whether the container with name FILENAME is a suitable G13
401    container.  This function may even be called on a mounted
402    container.  */
403 gpg_error_t
404 g13_is_container (ctrl_t ctrl, const char *filename)
405 {
406   gpg_error_t err;
407   estream_t fp = NULL;
408   size_t dummy;
409
410   (void)ctrl;
411
412   /* Read just the prefix of the header.  */
413   err = read_keyblob_prefix (filename, &fp, &dummy);
414   if (!err)
415     es_fclose (fp);
416   return err;
417 }