g13: Move some function around.
[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 "mountinfo.h"
37 #include "runner.h"
38 #include "host2net.h"
39 #include "server.h"  /*(g13_keyblob_decrypt)*/
40 #include "../common/sysutils.h"
41
42
43 /* Mount the container with name FILENAME at MOUNTPOINT.  */
44 gpg_error_t
45 g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
46 {
47   gpg_error_t err;
48   dotlock_t lock;
49   int needs_syshelp;
50   void *enckeyblob = NULL;
51   size_t enckeybloblen;
52   void *keyblob = NULL;
53   size_t keybloblen;
54   tupledesc_t tuples = NULL;
55   size_t n;
56   const unsigned char *value;
57   int conttype;
58   unsigned int rid;
59   char *mountpoint_buffer = NULL;
60
61   /* A quick check to see whether the container exists.  */
62   if (access (filename, R_OK))
63     return gpg_error_from_syserror ();
64
65   /* Decide whether we need to use the g13-syshelp because we can't
66      use lock files for them.  This is most likely the case for device
67      files; thus we test for this.  FIXME: The correct solution would
68      be to call g13-syshelp to match the file against the g13tab.  */
69   needs_syshelp = !strncmp (filename, "/dev/", 5);
70
71   if (!mountpoint)
72     {
73       mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
74       if (!mountpoint_buffer)
75         return gpg_error_from_syserror ();
76       if (!gnupg_mkdtemp (mountpoint_buffer))
77         {
78           err = gpg_error_from_syserror ();
79           log_error (_("can't create directory '%s': %s\n"),
80                      "/tmp/g13-XXXXXX", gpg_strerror (err));
81           xfree (mountpoint_buffer);
82           return err;
83         }
84       mountpoint = mountpoint_buffer;
85     }
86
87   err = 0;
88   if (needs_syshelp)
89     lock = NULL;
90   else
91     {
92       /* Try to take a lock.  */
93       lock = dotlock_create (filename, 0);
94       if (!lock)
95         {
96           xfree (mountpoint_buffer);
97           return gpg_error_from_syserror ();
98         }
99
100       if (dotlock_take (lock, 0))
101         {
102           err = gpg_error_from_syserror ();
103           goto leave;
104         }
105     }
106
107   /* Check again that the file exists.  */
108   {
109     struct stat sb;
110
111     if (stat (filename, &sb))
112       {
113         err = gpg_error_from_syserror ();
114         goto leave;
115       }
116   }
117
118   /* Read the encrypted keyblob.  */
119   /* Fixme: Should we move this to syshelp for dm-crypt or do we
120      assume that the encrypted device is world readable?  */
121   err = g13_keyblob_read (filename, &enckeyblob, &enckeybloblen);
122   if (err)
123     goto leave;
124
125   /* Decrypt that keyblob and store it in a tuple descriptor.  */
126   err = g13_keyblob_decrypt (ctrl, enckeyblob, enckeybloblen,
127                              &keyblob, &keybloblen);
128   if (err)
129     goto leave;
130   xfree (enckeyblob);
131   enckeyblob = NULL;
132
133   err = create_tupledesc (&tuples, keyblob, keybloblen);
134   if (!err)
135     keyblob = NULL;
136   else
137     {
138       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
139         log_error ("unknown keyblob version\n");
140       goto leave;
141     }
142   if (opt.verbose)
143     dump_tupledesc (tuples);
144
145   value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
146   if (!value || n != 2)
147     conttype = 0;
148   else
149     conttype = (value[0] << 8 | value[1]);
150   if (!be_is_supported_conttype (conttype))
151     {
152       log_error ("content type %d is not supported\n", conttype);
153       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
154       goto leave;
155     }
156   err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
157   if (err)
158     ;
159   else if (conttype == CONTTYPE_DM_CRYPT)
160     g13_request_shutdown ();
161   else
162     {
163       /* Unless this is a DM-CRYPT mount we put it into our mounttable
164          so that we can manage the mounts ourselves.  For dm-crypt we
165          do not keep a process to monitor he mounts (for now).  */
166       err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
167                                  !!mountpoint_buffer);
168       /* Fixme: What shall we do if this fails?  Add a provisional
169          mountinfo entry first and remove it on error? */
170       if (!err)
171         {
172           char *tmp = percent_plus_escape (mountpoint);
173           if (!tmp)
174             err = gpg_error_from_syserror ();
175           else
176             {
177               g13_status (ctrl, STATUS_MOUNTPOINT, tmp, NULL);
178               xfree (tmp);
179             }
180         }
181     }
182
183  leave:
184   destroy_tupledesc (tuples);
185   xfree (keyblob);
186   xfree (enckeyblob);
187   dotlock_destroy (lock);
188   xfree (mountpoint_buffer);
189   return err;
190 }
191
192
193 /* Unmount the container with name FILENAME or the one mounted at
194    MOUNTPOINT.  If both are given the FILENAME takes precedence.  */
195 gpg_error_t
196 g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
197 {
198   gpg_error_t err;
199   unsigned int rid;
200   runner_t runner;
201
202   (void)ctrl;
203
204   if (!filename && !mountpoint)
205     return gpg_error (GPG_ERR_ENOENT);
206   err = mountinfo_find_mount (filename, mountpoint, &rid);
207   if (err)
208     return err;
209
210   runner = runner_find_by_rid (rid);
211   if (!runner)
212     {
213       log_error ("runner %u not found\n", rid);
214       return gpg_error (GPG_ERR_NOT_FOUND);
215     }
216
217   runner_cancel (runner);
218   runner_release (runner);
219
220   return 0;
221 }