Keep on hacking on g13. A simple --create and --mount does now work.
[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 "call-gpg.h"
37 #include "estream.h"
38
39
40 /* Parse the header prefix and return the length of the entire header.  */
41 static gpg_error_t
42 parse_header (const char *filename, 
43               const unsigned char *packet, size_t packetlen,
44               size_t *r_headerlen)
45 {
46   unsigned int len;
47
48   if (packetlen != 32)
49     return gpg_error (GPG_ERR_BUG);
50
51   len = ((packet[2] << 24) | (packet[3] << 16)
52          | (packet[4] << 8) | packet[5]);
53   if (packet[0] != (0xc0|61) || len < 26
54       || memcmp (packet+6, "GnuPG/G13", 10))
55     {
56       log_error ("file `%s' is not valid container\n", filename);
57       return gpg_error (GPG_ERR_INV_OBJ);
58     }
59   if (packet[16] != 1)
60     {
61       log_error ("unknown version %u of container `%s'\n",
62                  (unsigned int)packet[16], filename);
63       return gpg_error (GPG_ERR_INV_OBJ);
64     }
65   if (packet[17] || packet[18]
66       || packet[26] || packet[27] || packet[28] || packet[29] 
67       || packet[30] || packet[31])
68     log_info ("WARNING: unknown meta information in `%s'\n", filename);
69   if (packet[19])
70     log_info ("WARNING: OS flag is not supported in `%s'\n", filename);
71   if (packet[24] != 1 || packet[25] != 0)
72     {
73       log_error ("meta data copies in `%s' are not supported\n", filename);
74       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
75     }
76
77   len = ((packet[20] << 24) | (packet[21] << 16)
78          | (packet[22] << 8) | packet[23]);
79
80   /* Do a basic sanity check on the length.  */
81   if (len < 32 || len > 1024*1024)
82     {
83       log_error ("bad length given in container `%s'\n", filename);
84       return gpg_error (GPG_ERR_INV_OBJ);
85     }
86      
87   *r_headerlen = len;
88   return 0;
89 }
90
91
92
93 /* Read the keyblob at FILENAME.  The caller should have acquired a
94    lockfile and checked that the file exists.  */
95 static gpg_error_t
96 read_keyblob (const char *filename, 
97               void **r_enckeyblob, size_t *r_enckeybloblen)
98 {
99   gpg_error_t err;
100   estream_t fp;
101   unsigned char packet[32];
102   size_t headerlen, msglen;
103   void *msg = NULL;
104   
105   *r_enckeyblob = NULL;
106   *r_enckeybloblen = 0;
107
108   fp = es_fopen (filename, "rb");
109   if (!fp)
110     {
111       err = gpg_error_from_syserror ();
112       log_error ("error reading `%s': %s\n", 
113                  filename, gpg_strerror (err));
114       return err;
115     }
116   
117   /* Read the header.  It is defined as 32 bytes thus we read it in one go.  */
118   if (es_fread (packet, 32, 1, fp) != 1)
119     {
120       err = gpg_error_from_syserror ();
121       log_error ("error reading the header of `%s': %s\n",
122                  filename, gpg_strerror (err));
123       goto leave;
124     }
125   
126   err = parse_header (filename, packet, 32, &headerlen);
127   if (err)
128     goto leave;
129   
130   if (opt.verbose)
131     log_info ("header length of `%s' is %zu\n", filename, headerlen);
132
133   /* Read everything including the padding.  We should eventually do a
134      regular OpenPGP parsing to detect the padding packet and pass
135      only the actual used OpenPGP data to the engine.  This is in
136      particular required when supporting CMS which will be
137      encapsulated in an OpenPGP packet.  */
138   assert (headerlen >= 32);
139   msglen = headerlen - 32;
140   if (!msglen)
141     {
142       err = gpg_error (GPG_ERR_NO_DATA);
143       goto leave;
144     }
145   msg = xtrymalloc (msglen);
146   if (!msglen)
147     {
148       err = gpg_error_from_syserror ();
149       goto leave;
150     }
151   if (es_fread (msg, msglen, 1, fp) != 1)
152     {
153       err = gpg_error_from_syserror ();
154       log_error ("error reading keyblob of `%s': %s\n",
155                  filename, gpg_strerror (err));
156       goto leave;
157     }
158
159   *r_enckeyblob = msg;
160   msg = NULL;
161   *r_enckeybloblen = msglen;
162
163  leave:
164   xfree (msg);
165   es_fclose (fp);
166
167   return err;
168 }
169
170
171
172
173 /* Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result at
174    (R_KEYBLOB, R_KEYBLOBLEN).  Returns 0 on success or an error code.
175    On error R_KEYBLOB is set to NULL.  */
176 static gpg_error_t
177 decrypt_keyblob (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
178                  void **r_keyblob, size_t *r_keybloblen)
179 {
180   gpg_error_t err;
181
182   /* FIXME:  For now we only implement OpenPGP.  */
183   err = gpg_decrypt_blob (ctrl, enckeyblob, enckeybloblen,
184                           r_keyblob, r_keybloblen);
185
186   return err;
187 }
188
189
190 static void
191 dump_keyblob (tupledesc_t tuples)
192 {
193   size_t n;
194   unsigned int tag;
195   const void *value;
196
197   log_info ("keyblob dump:\n");
198   tag = KEYBLOB_TAG_BLOBVERSION;
199   value = find_tuple (tuples, tag, &n);
200   while (value)
201     {
202       log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
203       if (tag == KEYBLOB_TAG_ENCKEY
204           ||  tag == KEYBLOB_TAG_MACKEY)
205         log_printf ("[confidential]\n");
206       else if (!n)
207         log_printf ("[none]\n");
208       else
209         log_printhex ("", value, n);
210       value = next_tuple (tuples, &tag, &n);
211     }
212 }
213
214
215
216 /* Mount the container with name FILENAME at MOUNTPOINT.  */
217 gpg_error_t
218 g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
219 {
220   gpg_error_t err;
221   dotlock_t lock;
222   void *enckeyblob = NULL;
223   size_t enckeybloblen;
224   void *keyblob = NULL;
225   size_t keybloblen;
226   tupledesc_t tuples = NULL;
227   size_t n;
228   const unsigned char *value;
229   int conttype;
230
231   /* A quick check to see whether the container exists.  */
232   if (access (filename, R_OK))
233     return gpg_error_from_syserror ();
234
235   /* Try to take a lock.  */
236   lock = create_dotlock (filename);
237   if (!lock)
238     return gpg_error_from_syserror ();
239
240   if (make_dotlock (lock, 0))
241     {
242       err = gpg_error_from_syserror ();
243       goto leave;
244     }
245   else
246     err = 0;
247
248   /* Check again that the file exists.  */
249   {
250     struct stat sb;
251     
252     if (stat (filename, &sb))
253       {
254         err = gpg_error_from_syserror ();
255         goto leave;
256       }
257   }
258
259   /* Read the encrypted keyblob.  */
260   err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
261   if (err)
262     goto leave;
263
264   /* Decrypt that keyblob and store it in a tuple descriptor.  */
265   err = decrypt_keyblob (ctrl, enckeyblob, enckeybloblen,
266                          &keyblob, &keybloblen);
267   if (err)
268     goto leave;
269   xfree (enckeyblob);
270   enckeyblob = NULL;
271
272   err = create_tupledesc (&tuples, keyblob, keybloblen);
273   if (!err)
274     keyblob = NULL;
275   else
276     {
277       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
278         log_error ("unknown keyblob version\n");
279       goto leave;
280     }
281   if (opt.verbose)
282     dump_keyblob (tuples);
283
284   value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
285   if (!value || n != 2)
286     conttype = 0;
287   else
288     conttype = (value[0] << 8 | value[1]);
289   if (!be_is_supported_conttype (conttype))
290     {
291       log_error ("content type %d is not supported\n", conttype);
292       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
293       goto leave;
294     }
295   err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples);
296
297  leave:
298   destroy_tupledesc (tuples);
299   xfree (keyblob);
300   xfree (enckeyblob);
301   destroy_dotlock (lock);
302   return err;
303 }