Line data Source code
1 : /* keybox-init.c - Initialization of the library
2 : * Copyright (C) 2001 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 <https://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 : #include <stdlib.h>
22 : #include <stdio.h>
23 : #include <string.h>
24 : #include <unistd.h>
25 : #include <assert.h>
26 :
27 : #include "keybox-defs.h"
28 : #include "../common/mischelp.h"
29 :
30 : static KB_NAME kb_names;
31 :
32 :
33 : /* Register a filename for plain keybox files. Returns 0 on success,
34 : * GPG_ERR_EEXIST if it has already been registered, or another error
35 : * code. On success or with error code GPG_ERR_EEXIST a token usable
36 : * to access the keybox handle is stored at R_TOKEN, NULL is stored
37 : * for all other errors. */
38 : gpg_error_t
39 1118 : keybox_register_file (const char *fname, int secret, void **r_token)
40 : {
41 : KB_NAME kr;
42 :
43 1118 : *r_token = NULL;
44 :
45 1118 : for (kr=kb_names; kr; kr = kr->next)
46 : {
47 0 : if (same_file_p (kr->fname, fname) )
48 : {
49 0 : *r_token = kr;
50 0 : return gpg_error (GPG_ERR_EEXIST); /* Already registered. */
51 : }
52 : }
53 :
54 1118 : kr = xtrymalloc (sizeof *kr + strlen (fname));
55 1118 : if (!kr)
56 0 : return gpg_error_from_syserror ();
57 1118 : strcpy (kr->fname, fname);
58 1118 : kr->secret = !!secret;
59 :
60 1118 : kr->handle_table = NULL;
61 1118 : kr->handle_table_size = 0;
62 :
63 1118 : kr->lockhd = NULL;
64 1118 : kr->is_locked = 0;
65 1118 : kr->did_full_scan = 0;
66 : /* keep a list of all issued pointers */
67 1118 : kr->next = kb_names;
68 1118 : kb_names = kr;
69 :
70 : /* create the offset table the first time a function here is used */
71 : /* if (!kb_offtbl) */
72 : /* kb_offtbl = new_offset_hash_table (); */
73 :
74 1118 : *r_token = kr;
75 1118 : return 0;
76 : }
77 :
78 : int
79 651 : keybox_is_writable (void *token)
80 : {
81 651 : KB_NAME r = token;
82 :
83 651 : return r? !access (r->fname, W_OK) : 0;
84 : }
85 :
86 :
87 :
88 : static KEYBOX_HANDLE
89 3458 : do_keybox_new (KB_NAME resource, int secret, int for_openpgp)
90 : {
91 : KEYBOX_HANDLE hd;
92 : int idx;
93 :
94 3458 : assert (resource && !resource->secret == !secret);
95 3458 : hd = xtrycalloc (1, sizeof *hd);
96 3458 : if (hd)
97 : {
98 3458 : hd->kb = resource;
99 3458 : hd->secret = !!secret;
100 3458 : hd->for_openpgp = for_openpgp;
101 3458 : if (!resource->handle_table)
102 : {
103 996 : resource->handle_table_size = 3;
104 996 : resource->handle_table = xtrycalloc (resource->handle_table_size,
105 : sizeof *resource->handle_table);
106 996 : if (!resource->handle_table)
107 : {
108 0 : resource->handle_table_size = 0;
109 0 : xfree (hd);
110 0 : return NULL;
111 : }
112 : }
113 3849 : for (idx=0; idx < resource->handle_table_size; idx++)
114 3849 : if (!resource->handle_table[idx])
115 : {
116 3458 : resource->handle_table[idx] = hd;
117 3458 : break;
118 : }
119 3458 : if (!(idx < resource->handle_table_size))
120 : {
121 : KEYBOX_HANDLE *tmptbl;
122 : size_t newsize;
123 :
124 0 : newsize = resource->handle_table_size + 5;
125 0 : tmptbl = xtryrealloc (resource->handle_table,
126 : newsize * sizeof (*tmptbl));
127 0 : if (!tmptbl)
128 : {
129 0 : xfree (hd);
130 0 : return NULL;
131 : }
132 0 : resource->handle_table = tmptbl;
133 0 : resource->handle_table_size = newsize;
134 0 : resource->handle_table[idx] = hd;
135 0 : for (idx++; idx < resource->handle_table_size; idx++)
136 0 : resource->handle_table[idx] = NULL;
137 : }
138 : }
139 3458 : return hd;
140 : }
141 :
142 :
143 : /* Create a new handle for the resource associated with TOKEN. SECRET
144 : is just a cross-check. This is the OpenPGP version. The returned
145 : handle must be released using keybox_release. */
146 : KEYBOX_HANDLE
147 3446 : keybox_new_openpgp (void *token, int secret)
148 : {
149 3446 : KB_NAME resource = token;
150 :
151 3446 : return do_keybox_new (resource, secret, 1);
152 : }
153 :
154 : /* Create a new handle for the resource associated with TOKEN. SECRET
155 : is just a cross-check. This is the X.509 version. The returned
156 : handle must be released using keybox_release. */
157 : KEYBOX_HANDLE
158 12 : keybox_new_x509 (void *token, int secret)
159 : {
160 12 : KB_NAME resource = token;
161 :
162 12 : return do_keybox_new (resource, secret, 0);
163 : }
164 :
165 :
166 : void
167 3458 : keybox_release (KEYBOX_HANDLE hd)
168 : {
169 3458 : if (!hd)
170 3458 : return;
171 3458 : if (hd->kb->handle_table)
172 : {
173 : int idx;
174 13832 : for (idx=0; idx < hd->kb->handle_table_size; idx++)
175 10374 : if (hd->kb->handle_table[idx] == hd)
176 3458 : hd->kb->handle_table[idx] = NULL;
177 : }
178 3458 : _keybox_release_blob (hd->found.blob);
179 3458 : _keybox_release_blob (hd->saved_found.blob);
180 3458 : if (hd->fp)
181 : {
182 3195 : fclose (hd->fp);
183 3195 : hd->fp = NULL;
184 : }
185 3458 : xfree (hd->word_match.name);
186 3458 : xfree (hd->word_match.pattern);
187 3458 : xfree (hd);
188 : }
189 :
190 :
191 : /* Save the current found state in HD for later retrieval by
192 : keybox_restore_found_state. Only one state may be saved. */
193 : void
194 2 : keybox_push_found_state (KEYBOX_HANDLE hd)
195 : {
196 2 : if (hd->saved_found.blob)
197 : {
198 0 : _keybox_release_blob (hd->saved_found.blob);
199 0 : hd->saved_found.blob = NULL;
200 : }
201 2 : hd->saved_found = hd->found;
202 2 : hd->found.blob = NULL;
203 2 : }
204 :
205 :
206 : /* Restore the saved found state in HD. */
207 : void
208 2 : keybox_pop_found_state (KEYBOX_HANDLE hd)
209 : {
210 2 : if (hd->found.blob)
211 : {
212 0 : _keybox_release_blob (hd->found.blob);
213 0 : hd->found.blob = NULL;
214 : }
215 2 : hd->found = hd->saved_found;
216 2 : hd->saved_found.blob = NULL;
217 2 : }
218 :
219 :
220 : const char *
221 0 : keybox_get_resource_name (KEYBOX_HANDLE hd)
222 : {
223 0 : if (!hd || !hd->kb)
224 0 : return NULL;
225 0 : return hd->kb->fname;
226 : }
227 :
228 : int
229 6 : keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes)
230 : {
231 6 : if (!hd)
232 0 : return gpg_error (GPG_ERR_INV_HANDLE);
233 6 : hd->ephemeral = yes;
234 6 : return 0;
235 : }
236 :
237 :
238 : /* Close the file of the resource identified by HD. For consistent
239 : results this function closes the files of all handles pointing to
240 : the resource identified by HD. */
241 : void
242 255 : _keybox_close_file (KEYBOX_HANDLE hd)
243 : {
244 : int idx;
245 : KEYBOX_HANDLE roverhd;
246 :
247 255 : if (!hd || !hd->kb || !hd->kb->handle_table)
248 255 : return;
249 :
250 1020 : for (idx=0; idx < hd->kb->handle_table_size; idx++)
251 765 : if ((roverhd = hd->kb->handle_table[idx]))
252 : {
253 255 : if (roverhd->fp)
254 : {
255 99 : fclose (roverhd->fp);
256 99 : roverhd->fp = NULL;
257 : }
258 : }
259 255 : assert (!hd->fp);
260 : }
261 :
262 :
263 : /*
264 : * Lock the keybox at handle HD, or unlock if YES is false.
265 : */
266 : gpg_error_t
267 498 : keybox_lock (KEYBOX_HANDLE hd, int yes)
268 : {
269 498 : gpg_error_t err = 0;
270 498 : KB_NAME kb = hd->kb;
271 :
272 498 : if (!keybox_is_writable (kb))
273 0 : return 0;
274 :
275 : /* Make sure the lock handle has been created. */
276 498 : if (!kb->lockhd)
277 : {
278 109 : kb->lockhd = dotlock_create (kb->fname, 0);
279 109 : if (!kb->lockhd)
280 : {
281 0 : err = gpg_error_from_syserror ();
282 0 : log_info ("can't allocate lock for '%s'\n", kb->fname );
283 0 : return err;
284 : }
285 : }
286 :
287 498 : if (yes) /* Take the lock. */
288 : {
289 249 : if (!kb->is_locked)
290 : {
291 : #ifdef HAVE_W32_SYSTEM
292 : /* Under Windows we need to close the file before we try
293 : * to lock it. This is because another process might have
294 : * taken the lock and is using keybox_file_rename to
295 : * rename the base file. How if our dotlock_take below is
296 : * waiting for the lock but we have the base file still
297 : * open, keybox_file_rename will never succeed as we are
298 : * in a deadlock. */
299 : if (hd->fp)
300 : {
301 : fclose (hd->fp);
302 : hd->fp = NULL;
303 : }
304 : #endif /*HAVE_W32_SYSTEM*/
305 249 : if (dotlock_take (kb->lockhd, -1))
306 : {
307 0 : err = gpg_error_from_syserror ();
308 0 : log_info ("can't lock '%s'\n", kb->fname );
309 : }
310 : else
311 249 : kb->is_locked = 1;
312 : }
313 : }
314 : else /* Release the lock. */
315 : {
316 249 : if (kb->is_locked)
317 : {
318 249 : if (dotlock_release (kb->lockhd))
319 : {
320 0 : err = gpg_error_from_syserror ();
321 0 : log_info ("can't unlock '%s'\n", kb->fname );
322 : }
323 : else
324 249 : kb->is_locked = 0;
325 : }
326 : }
327 :
328 498 : return err;
329 : }
|