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/>.
36 #include "../common/sysutils.h"
38 #include "mountinfo.h"
43 /* Parse the header prefix and return the length of the entire header. */
45 parse_header (const char *filename,
46 const unsigned char *packet, size_t packetlen,
52 return gpg_error (GPG_ERR_BUG);
54 len = buf32_to_uint (packet+2);
55 if (packet[0] != (0xc0|61) || len < 26
56 || memcmp (packet+6, "GnuPG/G13", 10))
58 log_error ("file '%s' is not valid container\n", filename);
59 return gpg_error (GPG_ERR_INV_OBJ);
63 log_error ("unknown version %u of container '%s'\n",
64 (unsigned int)packet[16], filename);
65 return gpg_error (GPG_ERR_INV_OBJ);
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);
72 log_info ("WARNING: OS flag is not supported in '%s'\n", filename);
73 if (packet[24] != 1 || packet[25] != 0)
75 log_error ("meta data copies in '%s' are not supported\n", filename);
76 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
79 len = buf32_to_uint (packet+20);
81 /* Do a basic sanity check on the length. */
82 if (len < 32 || len > 1024*1024)
84 log_error ("bad length given in container '%s'\n", filename);
85 return gpg_error (GPG_ERR_INV_OBJ);
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. */
97 read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
101 unsigned char packet[32];
105 fp = es_fopen (filename, "rb");
108 err = gpg_error_from_syserror ();
109 log_error ("error reading '%s': %s\n", filename, gpg_strerror (err));
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)
116 err = gpg_error_from_syserror ();
117 log_error ("error reading the header of '%s': %s\n",
118 filename, gpg_strerror (err));
123 err = parse_header (filename, packet, 32, r_headerlen);
133 /* Read the keyblob at FILENAME. The caller should have acquired a
134 lockfile and checked that the file exists. */
136 read_keyblob (const char *filename,
137 void **r_enckeyblob, size_t *r_enckeybloblen)
141 size_t headerlen = 0;
145 *r_enckeyblob = NULL;
146 *r_enckeybloblen = 0;
148 err = read_keyblob_prefix (filename, &fp, &headerlen);
153 log_info ("header length of '%s' is %zu\n", filename, headerlen);
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;
164 err = gpg_error (GPG_ERR_NO_DATA);
167 msg = xtrymalloc (msglen);
170 err = gpg_error_from_syserror ();
173 if (es_fread (msg, msglen, 1, fp) != 1)
175 err = gpg_error_from_syserror ();
176 log_error ("error reading keyblob of '%s': %s\n",
177 filename, gpg_strerror (err));
183 *r_enckeybloblen = msglen;
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. */
199 decrypt_keyblob (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
200 void **r_keyblob, size_t *r_keybloblen)
204 /* FIXME: For now we only implement OpenPGP. */
205 err = gpg_decrypt_blob (ctrl, enckeyblob, enckeybloblen,
206 r_keyblob, r_keybloblen);
213 dump_keyblob (tupledesc_t tuples)
219 log_info ("keyblob dump:\n");
220 tag = KEYBLOB_TAG_BLOBVERSION;
221 value = find_tuple (tuples, tag, &n);
224 log_info (" tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
225 if (tag == KEYBLOB_TAG_ENCKEY
226 || tag == KEYBLOB_TAG_MACKEY)
227 log_printf ("[confidential]\n");
229 log_printf ("[none]\n");
231 log_printhex ("", value, n);
232 value = next_tuple (tuples, &tag, &n);
238 /* Mount the container with name FILENAME at MOUNTPOINT. */
240 g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
244 void *enckeyblob = NULL;
245 size_t enckeybloblen;
246 void *keyblob = NULL;
248 tupledesc_t tuples = NULL;
250 const unsigned char *value;
253 char *mountpoint_buffer = NULL;
255 /* A quick check to see whether the container exists. */
256 if (access (filename, R_OK))
257 return gpg_error_from_syserror ();
261 mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
262 if (!mountpoint_buffer)
263 return gpg_error_from_syserror ();
264 if (!gnupg_mkdtemp (mountpoint_buffer))
266 err = gpg_error_from_syserror ();
267 log_error (_("can't create directory '%s': %s\n"),
268 "/tmp/g13-XXXXXX", gpg_strerror (err));
269 xfree (mountpoint_buffer);
272 mountpoint = mountpoint_buffer;
275 /* Try to take a lock. */
276 lock = dotlock_create (filename, 0);
279 xfree (mountpoint_buffer);
280 return gpg_error_from_syserror ();
283 if (dotlock_take (lock, 0))
285 err = gpg_error_from_syserror ();
291 /* Check again that the file exists. */
295 if (stat (filename, &sb))
297 err = gpg_error_from_syserror ();
302 /* Read the encrypted keyblob. */
303 err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
307 /* Decrypt that keyblob and store it in a tuple descriptor. */
308 err = decrypt_keyblob (ctrl, enckeyblob, enckeybloblen,
309 &keyblob, &keybloblen);
315 err = create_tupledesc (&tuples, keyblob, keybloblen);
320 if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
321 log_error ("unknown keyblob version\n");
325 dump_keyblob (tuples);
327 value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
328 if (!value || n != 2)
331 conttype = (value[0] << 8 | value[1]);
332 if (!be_is_supported_conttype (conttype))
334 log_error ("content type %d is not supported\n", conttype);
335 err = gpg_error (GPG_ERR_NOT_SUPPORTED);
338 err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
341 err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
342 !!mountpoint_buffer);
343 /* Fixme: What shall we do if this fails? Add a provisional
344 mountinfo entry first and remove it on error? */
347 char *tmp = percent_plus_escape (mountpoint);
349 err = gpg_error_from_syserror ();
352 g13_status (ctrl, STATUS_MOUNTPOINT, tmp, NULL);
359 destroy_tupledesc (tuples);
362 dotlock_destroy (lock);
363 xfree (mountpoint_buffer);
368 /* Unmount the container with name FILENAME or the one mounted at
369 MOUNTPOINT. If both are given the FILENAME takes precedence. */
371 g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
379 if (!filename && !mountpoint)
380 return gpg_error (GPG_ERR_ENOENT);
381 err = mountinfo_find_mount (filename, mountpoint, &rid);
385 runner = runner_find_by_rid (rid);
388 log_error ("runner %u not found\n", rid);
389 return gpg_error (GPG_ERR_NOT_FOUND);
392 runner_cancel (runner);
393 runner_release (runner);
399 /* Test whether the container with name FILENAME is a suitable G13
400 container. This function may even be called on a mounted
403 g13_is_container (ctrl_t ctrl, const char *filename)
411 /* Read just the prefix of the header. */
412 err = read_keyblob_prefix (filename, &fp, &dummy);