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