Keep on hacking on g13. A simple --create and --mount does now work.
[gnupg.git] / g13 / mount.c
blob85851e9a80664f696059240d53c4f43b69462e28
1 /* mount.c - Mount a crypto container
2 * Copyright (C) 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
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>
29 #include "g13.h"
30 #include "i18n.h"
31 #include "mount.h"
33 #include "keyblob.h"
34 #include "backend.h"
35 #include "utils.h"
36 #include "call-gpg.h"
37 #include "estream.h"
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)
46 unsigned int len;
48 if (packetlen != 32)
49 return gpg_error (GPG_ERR_BUG);
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))
56 log_error ("file `%s' is not valid container\n", filename);
57 return gpg_error (GPG_ERR_INV_OBJ);
59 if (packet[16] != 1)
61 log_error ("unknown version %u of container `%s'\n",
62 (unsigned int)packet[16], filename);
63 return gpg_error (GPG_ERR_INV_OBJ);
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)
73 log_error ("meta data copies in `%s' are not supported\n", filename);
74 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
77 len = ((packet[20] << 24) | (packet[21] << 16)
78 | (packet[22] << 8) | packet[23]);
80 /* Do a basic sanity check on the length. */
81 if (len < 32 || len > 1024*1024)
83 log_error ("bad length given in container `%s'\n", filename);
84 return gpg_error (GPG_ERR_INV_OBJ);
87 *r_headerlen = len;
88 return 0;
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)
99 gpg_error_t err;
100 estream_t fp;
101 unsigned char packet[32];
102 size_t headerlen, msglen;
103 void *msg = NULL;
105 *r_enckeyblob = NULL;
106 *r_enckeybloblen = 0;
108 fp = es_fopen (filename, "rb");
109 if (!fp)
111 err = gpg_error_from_syserror ();
112 log_error ("error reading `%s': %s\n",
113 filename, gpg_strerror (err));
114 return err;
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)
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;
126 err = parse_header (filename, packet, 32, &headerlen);
127 if (err)
128 goto leave;
130 if (opt.verbose)
131 log_info ("header length of `%s' is %zu\n", filename, headerlen);
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)
142 err = gpg_error (GPG_ERR_NO_DATA);
143 goto leave;
145 msg = xtrymalloc (msglen);
146 if (!msglen)
148 err = gpg_error_from_syserror ();
149 goto leave;
151 if (es_fread (msg, msglen, 1, fp) != 1)
153 err = gpg_error_from_syserror ();
154 log_error ("error reading keyblob of `%s': %s\n",
155 filename, gpg_strerror (err));
156 goto leave;
159 *r_enckeyblob = msg;
160 msg = NULL;
161 *r_enckeybloblen = msglen;
163 leave:
164 xfree (msg);
165 es_fclose (fp);
167 return err;
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)
180 gpg_error_t err;
182 /* FIXME: For now we only implement OpenPGP. */
183 err = gpg_decrypt_blob (ctrl, enckeyblob, enckeybloblen,
184 r_keyblob, r_keybloblen);
186 return err;
190 static void
191 dump_keyblob (tupledesc_t tuples)
193 size_t n;
194 unsigned int tag;
195 const void *value;
197 log_info ("keyblob dump:\n");
198 tag = KEYBLOB_TAG_BLOBVERSION;
199 value = find_tuple (tuples, tag, &n);
200 while (value)
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);
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)
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;
231 /* A quick check to see whether the container exists. */
232 if (access (filename, R_OK))
233 return gpg_error_from_syserror ();
235 /* Try to take a lock. */
236 lock = create_dotlock (filename);
237 if (!lock)
238 return gpg_error_from_syserror ();
240 if (make_dotlock (lock, 0))
242 err = gpg_error_from_syserror ();
243 goto leave;
245 else
246 err = 0;
248 /* Check again that the file exists. */
250 struct stat sb;
252 if (stat (filename, &sb))
254 err = gpg_error_from_syserror ();
255 goto leave;
259 /* Read the encrypted keyblob. */
260 err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
261 if (err)
262 goto leave;
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;
272 err = create_tupledesc (&tuples, keyblob, keybloblen);
273 if (!err)
274 keyblob = NULL;
275 else
277 if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
278 log_error ("unknown keyblob version\n");
279 goto leave;
281 if (opt.verbose)
282 dump_keyblob (tuples);
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))
291 log_error ("content type %d is not supported\n", conttype);
292 err = gpg_error (GPG_ERR_NOT_SUPPORTED);
293 goto leave;
295 err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples);
297 leave:
298 destroy_tupledesc (tuples);
299 xfree (keyblob);
300 xfree (enckeyblob);
301 destroy_dotlock (lock);
302 return err;