1 |
/* keycache.c - Caching for the pub- and the secring |
2 |
* Copyright (C) 2001-2004 Timo Schulz |
3 |
* |
4 |
* This file is part of MyGPGME. |
5 |
* |
6 |
* MyGPGME 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 2 of the License, or |
9 |
* (at your option) any later version. |
10 |
* |
11 |
* MyGPGME 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, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
19 |
*/ |
20 |
|
21 |
#include <stdio.h> |
22 |
#include <string.h> |
23 |
|
24 |
#include "context.h" |
25 |
#include "ops.h" |
26 |
#include "key.h" |
27 |
#include "util.h" |
28 |
|
29 |
|
30 |
gpgme_error_t |
31 |
gpgme_keycache_new( gpgme_keycache_t *r_ctx ) |
32 |
{ |
33 |
gpgme_keycache_t ctx; |
34 |
|
35 |
if( !r_ctx ) |
36 |
return mk_error( Invalid_Value ); |
37 |
ctx = calloc( 1, sizeof *ctx ); |
38 |
if( !ctx ) |
39 |
return mk_error( Out_Of_Core ); |
40 |
ctx->secret = 0; |
41 |
ctx->pos = 0; |
42 |
*r_ctx = ctx; |
43 |
return 0; |
44 |
} /* gpgme_keycache_new */ |
45 |
|
46 |
|
47 |
void |
48 |
gpgme_keycache_release (gpgme_keycache_t ctx) |
49 |
{ |
50 |
struct keycache_s * c, * c2; |
51 |
|
52 |
if (!ctx) |
53 |
return; |
54 |
|
55 |
for( c = ctx->item; c; c = c2 ) { |
56 |
c2 = c->next; |
57 |
gpgme_key_release( c->key ); |
58 |
c->key = NULL; |
59 |
safe_free( c ); |
60 |
} |
61 |
safe_free( ctx ); |
62 |
} /* gpgme_keycache_release */ |
63 |
|
64 |
|
65 |
void |
66 |
gpgme_keycache_set_cb (gpgme_keycache_t ctx, |
67 |
void (*cb)(void *, const char *, int, unsigned, unsigned), |
68 |
void * cb_value1, int cb_value2) |
69 |
{ |
70 |
if (!ctx) |
71 |
return; |
72 |
ctx->cb = cb; |
73 |
ctx->cb_value = cb_value1; |
74 |
ctx->cb_value2 = cb_value2; |
75 |
} |
76 |
|
77 |
|
78 |
gpgme_error_t |
79 |
gpgme_keycache_add_key (gpgme_keycache_t ctx, gpgme_key_t key, void **opaque) |
80 |
{ |
81 |
struct keycache_s * c, * n1; |
82 |
|
83 |
if( !ctx ) |
84 |
return mk_error(Invalid_Value); |
85 |
|
86 |
c = calloc( 1, sizeof *c ); |
87 |
if( !c ) |
88 |
return mk_error( Out_Of_Core ); |
89 |
c->key = key; |
90 |
if( !ctx->item ) |
91 |
ctx->item = c; |
92 |
else { |
93 |
for( n1 = ctx->item; n1 && n1->next; n1 = n1->next ) |
94 |
; |
95 |
n1->next = c; |
96 |
} |
97 |
if (opaque) |
98 |
*opaque = c; |
99 |
return 0; |
100 |
} /* gpgme_keycache_add_key */ |
101 |
|
102 |
|
103 |
#define is_deleted_item(c) (((c)->flags & 0x01)) |
104 |
#define has_keyid_len(pattern) (\ |
105 |
strlen (pattern) == 8 || strlen (pattern) == 10 || \ |
106 |
strlen (pattern) == 16 || strlen (pattern) == 18) |
107 |
|
108 |
|
109 |
static gpgme_error_t |
110 |
keycache_find_key (gpgme_keycache_t ctx, const char * pattern, int flags, |
111 |
gpgme_key_t * r_key, struct keycache_s ** r_item) |
112 |
{ |
113 |
struct keycache_s * c; |
114 |
struct subkey_s * s; |
115 |
struct user_id_s * u; |
116 |
const char *kid; |
117 |
|
118 |
if (!ctx || !r_key) |
119 |
return mk_error (Invalid_Value); |
120 |
|
121 |
if (strstr (pattern, "0x")) |
122 |
pattern += 2; |
123 |
/* XXX: this code is very slow, revamp it and use hash tables whenever |
124 |
it is possible. */ |
125 |
for (c = ctx->item; c; c = c->next) { |
126 |
if (is_deleted_item (c)) |
127 |
continue; |
128 |
for (s = &c->key->keys; s; s = s->next) { |
129 |
for (u = c->key->uids; u; u = u->next) { |
130 |
if (u->name && memistr (u->name, strlen (u->name), pattern)) { |
131 |
if (r_item) |
132 |
*r_item = c; |
133 |
*r_key = flags? c->pubpart : c->key; |
134 |
return 0; |
135 |
} |
136 |
} |
137 |
if (has_keyid_len (pattern)) |
138 |
kid = s->keyid; |
139 |
else |
140 |
kid = s->fingerprint; |
141 |
|
142 |
if (kid && memistr (kid, strlen (kid), pattern)) { |
143 |
if (r_item) |
144 |
*r_item = c; |
145 |
*r_key = flags? c->pubpart : c->key; |
146 |
return 0; |
147 |
} |
148 |
} |
149 |
} |
150 |
*r_key = NULL; |
151 |
return mk_error (General_Error); |
152 |
} /* keycache_find_key */ |
153 |
|
154 |
|
155 |
gpgme_error_t |
156 |
gpgme_keycache_find_key (gpgme_keycache_t ctx, const char * pattern, |
157 |
int flags, gpgme_key_t * r_key) |
158 |
{ |
159 |
return keycache_find_key (ctx, pattern, flags, r_key, NULL); |
160 |
} /* gpgme_keycache_find_key */ |
161 |
|
162 |
|
163 |
gpgme_error_t |
164 |
gpgme_keycache_update_key (gpgme_keycache_t ctx, int is_sec, void *opaque, |
165 |
const char *keyid) |
166 |
{ |
167 |
struct keycache_s *c = NULL; |
168 |
gpgme_key_t key=NULL, fndkey=NULL; |
169 |
gpgme_error_t err; |
170 |
|
171 |
err = gpgme_op_keylist_getkey (is_sec, keyid, &key); |
172 |
if (err) |
173 |
return err; |
174 |
err = keycache_find_key (ctx, keyid, 0, &fndkey, &c); |
175 |
if (!err && c != NULL) { |
176 |
gpgme_key_release (c->key); |
177 |
c->key = key; |
178 |
c->flags = 0; |
179 |
} |
180 |
else { |
181 |
gpgme_keycache_t pub = (gpgme_keycache_t)opaque; |
182 |
if (is_sec && !keycache_find_key (pub, keyid, 0, &fndkey, &c)) { |
183 |
fndkey->gloflags.is_protected = c->key->gloflags.is_protected; |
184 |
fndkey->gloflags.divert_to_card = c->key->gloflags.divert_to_card; |
185 |
} |
186 |
gpgme_keycache_add_key (ctx, key, &c); |
187 |
DEBUG3 ("keycache update: is_sec=%d keyid=%s %p\r\n", is_sec, keyid, c); |
188 |
if (is_sec) |
189 |
c->pubpart = fndkey; |
190 |
} |
191 |
return 0; |
192 |
} |
193 |
|
194 |
gpgme_error_t |
195 |
gpgme_keycache_delete_key (gpgme_keycache_t ctx, const char * pattern) |
196 |
{ |
197 |
struct keycache_s *c = NULL; |
198 |
gpgme_key_t key; |
199 |
gpgme_error_t rc; |
200 |
|
201 |
if (!ctx) |
202 |
return mk_error (Invalid_Value); |
203 |
rc = keycache_find_key (ctx, pattern, 0, &key, &c); |
204 |
if (!rc) |
205 |
c->flags |= 1; |
206 |
return rc; |
207 |
} /* gpgme_keycache_delete_key */ |
208 |
|
209 |
|
210 |
gpgme_error_t |
211 |
gpgme_keycache_init (gpgme_keycache_t ctx, const char *pattern, int secret) |
212 |
{ |
213 |
gpgme_error_t err; |
214 |
gpgme_ctx_t c; |
215 |
gpgme_key_t key; |
216 |
|
217 |
if (!ctx) |
218 |
return mk_error( Invalid_Value ); |
219 |
|
220 |
err = gpgme_new (&c); |
221 |
if (err) |
222 |
return err; |
223 |
if (ctx->cb) |
224 |
{ |
225 |
gpgme_control (c, GPGME_CTRL_CB_VAL, ctx->cb_value2); |
226 |
gpgme_set_progress_cb (c, ctx->cb, ctx->cb_value); |
227 |
} |
228 |
gpgme_control (c, GPGME_CTRL_LOGGING, 1); |
229 |
err = gpgme_op_keylist_start( c, pattern, secret ); |
230 |
while(!err) |
231 |
{ |
232 |
err = gpgme_op_keylist_next (c, &key); |
233 |
if (!err) |
234 |
err = gpgme_keycache_add_key (ctx, key, NULL); |
235 |
} |
236 |
if (err == GPGME_EOF) |
237 |
err = 0; |
238 |
if (gpgme_get_process_rc (c)) |
239 |
err = gpgme_check_logging (c); |
240 |
gpgme_release (c); |
241 |
return err; |
242 |
} /* gpgme_keycache_init */ |
243 |
|
244 |
|
245 |
gpgme_error_t |
246 |
gpgme_keycache_sync (gpgme_keycache_t pub, gpgme_keycache_t sec) |
247 |
{ |
248 |
struct keycache_s * c; |
249 |
const char * s; |
250 |
gpgme_key_t key; |
251 |
|
252 |
if (!pub || !sec) |
253 |
return mk_error (Invalid_Value); |
254 |
/* The GPG secret key listing does not contain much information |
255 |
so we add some information to the public key cache. */ |
256 |
for (c=sec->item; c; c=c->next) { |
257 |
s = gpgme_key_get_string_attr (c->key, GPGME_ATTR_KEYID, NULL, 0); |
258 |
if (!gpgme_keycache_find_key (pub, s, 0, &key)) { |
259 |
key->gloflags.is_protected = c->key->gloflags.is_protected; |
260 |
key->gloflags.divert_to_card = c->key->gloflags.divert_to_card; |
261 |
c->pubpart = key; |
262 |
} |
263 |
} |
264 |
return 0; |
265 |
} |
266 |
|
267 |
|
268 |
void |
269 |
gpgme_keycache_rewind (gpgme_keycache_t ctx) |
270 |
{ |
271 |
if (ctx) |
272 |
ctx->pos = 0; |
273 |
} /* gpgme_keycache_rewind */ |
274 |
|
275 |
|
276 |
int |
277 |
gpgme_keycache_count (gpgme_keycache_t ctx) |
278 |
{ |
279 |
struct keycache_s *c; |
280 |
int count = 0; |
281 |
|
282 |
if (!ctx) |
283 |
return 0; |
284 |
for (c = ctx->item; c; c = c->next) { |
285 |
if (is_deleted_item (c)) |
286 |
continue; |
287 |
count++; |
288 |
} |
289 |
return count; |
290 |
} /* gpgme_keycache_count */ |
291 |
|
292 |
|
293 |
gpgme_error_t |
294 |
gpgme_keycache_next_key (gpgme_keycache_t ctx, int flags, gpgme_key_t * r_key) |
295 |
{ |
296 |
if (!ctx || !r_key) |
297 |
return mk_error (Invalid_Value); |
298 |
|
299 |
if (!ctx->pos) |
300 |
ctx->tmp = ctx->item; |
301 |
|
302 |
if (!ctx->tmp || !ctx->tmp->key) { |
303 |
ctx->pos = 0; |
304 |
*r_key = NULL; |
305 |
return mk_error (Invalid_Value); |
306 |
} |
307 |
|
308 |
*r_key = flags? ctx->tmp->pubpart : ctx->tmp->key; |
309 |
|
310 |
ctx->tmp = ctx->tmp->next; |
311 |
ctx->pos++; |
312 |
|
313 |
return 0; |
314 |
} /* gpgme_keycache_next_key */ |