1 |
twoaday |
2 |
/* keylist.c - key listing |
2 |
|
|
* Copyright (C) 2000, 2001 Werner Koch (dd9jn), g10 Code GmbH |
3 |
twoaday |
17 |
* Copyright (C) 2002-2005 Timo Schulz |
4 |
twoaday |
2 |
* |
5 |
|
|
* This file is part of MyGPGME. |
6 |
|
|
* |
7 |
|
|
* MyGPGME is free software; you can redistribute it and/or modify |
8 |
|
|
* it under the terms of the GNU General Public License as published by |
9 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
10 |
|
|
* (at your option) any later version. |
11 |
|
|
* |
12 |
|
|
* MyGPGME is distributed in the hope that it will be useful, |
13 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
|
|
* GNU General Public License for more details. |
16 |
|
|
* |
17 |
|
|
* You should have received a copy of the GNU General Public License |
18 |
|
|
* along with this program; if not, write to the Free Software |
19 |
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
#include <stdio.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
#include <time.h> |
26 |
|
|
#include <ctype.h> |
27 |
|
|
#include <assert.h> |
28 |
|
|
#include <windows.h> |
29 |
|
|
|
30 |
|
|
#include "util.h" |
31 |
|
|
#include "context.h" |
32 |
|
|
#include "ops.h" |
33 |
|
|
#include "key.h" |
34 |
|
|
|
35 |
|
|
static void finish_key ( gpgme_ctx_t ctx ); |
36 |
|
|
|
37 |
|
|
|
38 |
|
|
static void |
39 |
|
|
keylist_status_handler( gpgme_ctx_t ctx, gpg_status_code_t code, char *args ) |
40 |
|
|
{ |
41 |
|
|
if( ctx->out_of_core ) |
42 |
|
|
return; |
43 |
|
|
|
44 |
|
|
switch( code ) { |
45 |
|
|
case STATUS_EOF: |
46 |
|
|
if( ctx->tmp_key ) |
47 |
|
|
finish_key( ctx ); |
48 |
|
|
break; |
49 |
|
|
|
50 |
|
|
default: /* ignore all other codes */ |
51 |
|
|
break; |
52 |
|
|
} |
53 |
|
|
} |
54 |
|
|
|
55 |
|
|
|
56 |
|
|
|
57 |
|
|
static time_t |
58 |
|
|
parse_timestamp( char * p ) |
59 |
|
|
{ |
60 |
|
|
return *p ? (time_t)strtoul( p, NULL, 10 ) : 0; |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
|
64 |
|
|
static void |
65 |
|
|
set_mainkey_trust_info( gpgme_key_t key, const char * s ) |
66 |
|
|
{ |
67 |
|
|
/* look at letters and stop at the first digit */ |
68 |
|
|
for( ; *s && !isdigit( *s ); s++ ) { |
69 |
|
|
switch( *s ) { |
70 |
|
|
case 'u': key->gloflags.ultimate = 1; |
71 |
|
|
key->validity = GPGME_VALIDITY_ULTIMATE; break; |
72 |
|
|
case '-': |
73 |
|
|
case 'q': key->validity = GPGME_VALIDITY_UNDEFINED; break; |
74 |
|
|
case 'm': key->validity = GPGME_VALIDITY_MARGINAL; break; |
75 |
|
|
case 'f': key->validity = GPGME_VALIDITY_FULL; break; |
76 |
|
|
case 'e': key->keys.flags.expired = 1; break; |
77 |
|
|
case 'r': key->keys.flags.revoked = 1; |
78 |
|
|
key->validity = GPGME_VALIDITY_REVOKED; break; |
79 |
|
|
case 'd': key->keys.flags.disabled = 1; break; |
80 |
|
|
case 'i': key->keys.flags.invalid = 1; break; |
81 |
|
|
} |
82 |
|
|
} |
83 |
|
|
} |
84 |
|
|
|
85 |
|
|
|
86 |
|
|
static void |
87 |
|
|
set_userid_flags (struct user_id_s * u, const char * s) |
88 |
|
|
{ |
89 |
|
|
/* look at letters and stop at the first digit */ |
90 |
|
|
for (; *s && !isdigit (*s); s++) { |
91 |
|
|
switch( *s ) { |
92 |
|
|
case 'r': u->flags.revoked = 1; |
93 |
|
|
u->validity = GPGME_VALIDITY_REVOKED; break; |
94 |
|
|
case 'i': u->flags.invalid = 1; |
95 |
|
|
u->validity = GPGME_VALIDITY_UNDEFINED; break; |
96 |
|
|
case 'n': u->validity = GPGME_VALIDITY_NEVER; break; |
97 |
|
|
case 'm': u->validity = GPGME_VALIDITY_MARGINAL; break; |
98 |
|
|
case 'f': u->validity = GPGME_VALIDITY_FULL; break; |
99 |
|
|
case 'u': u->validity = GPGME_VALIDITY_ULTIMATE; break; |
100 |
|
|
} |
101 |
|
|
} |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
static void |
105 |
|
|
set_subkey_trust_info( struct subkey_s * k, const char * s ) |
106 |
|
|
{ |
107 |
|
|
/* look at letters and stop at the first digit */ |
108 |
|
|
for( ; *s && !isdigit (*s); s++ ) { |
109 |
|
|
switch( *s ) { |
110 |
|
|
case 'e': k->flags.expired = 1; break; |
111 |
|
|
case 'r': k->flags.revoked = 1; break; |
112 |
|
|
case 'd': k->flags.disabled = 1; break; |
113 |
|
|
case 'i': k->flags.invalid = 1; break; |
114 |
|
|
} |
115 |
|
|
} |
116 |
|
|
} |
117 |
|
|
|
118 |
|
|
static void |
119 |
|
|
set_mainkey_capability( gpgme_key_t key, const char * s ) |
120 |
|
|
{ |
121 |
|
|
for( ; *s ; s++ ) { |
122 |
|
|
switch( *s ) { |
123 |
|
|
case 'a': key->keys.flags.can_auth = 1; break; |
124 |
|
|
case 'e': key->keys.flags.can_encrypt = 1; break; |
125 |
|
|
case 's': key->keys.flags.can_sign = 1; break; |
126 |
|
|
case 'c': key->keys.flags.can_certify = 1; break; |
127 |
|
|
case 'E': key->gloflags.can_encrypt = 1; break; |
128 |
|
|
case 'S': key->gloflags.can_sign = 1; break; |
129 |
|
|
case 'C': key->gloflags.can_certify = 1; break; |
130 |
|
|
case 'D': key->gloflags.disabled = 1; break; |
131 |
|
|
} |
132 |
|
|
} |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
static void |
136 |
|
|
set_subkey_capability (struct subkey_s * k, const char * s) |
137 |
|
|
{ |
138 |
|
|
for (; *s; s++) { |
139 |
|
|
switch (*s) { |
140 |
|
|
case 'a': k->flags.can_auth = 1; break; |
141 |
|
|
case 'e': k->flags.can_encrypt = 1; break; |
142 |
|
|
case 's': k->flags.can_sign = 1; break; |
143 |
|
|
case 'c': k->flags.can_certify = 1; break; |
144 |
|
|
} |
145 |
|
|
} |
146 |
|
|
} |
147 |
|
|
|
148 |
|
|
static void |
149 |
|
|
set_mainkey_ownertrust( gpgme_key_t key, const char * s ) |
150 |
|
|
{ |
151 |
|
|
switch( *s ) { |
152 |
|
|
case '-': key->otrust = GPGME_TRUST_UNKNOWN; break; |
153 |
|
|
case 'e': key->otrust = GPGME_TRUST_EXPIRED; break; |
154 |
|
|
case 'q': key->otrust = GPGME_TRUST_UNDEFINED; break; |
155 |
|
|
case 'n': key->otrust = GPGME_TRUST_NEVER; break; |
156 |
|
|
case 'm': key->otrust = GPGME_TRUST_MARGINAL; break; |
157 |
|
|
case 'f': key->otrust = GPGME_TRUST_FULLY; break; |
158 |
|
|
case 'u': key->otrust = GPGME_TRUST_ULTIMATE; break; |
159 |
|
|
default: key->otrust = GPGME_TRUST_UNKNOWN; break; |
160 |
|
|
} |
161 |
|
|
} |
162 |
|
|
|
163 |
|
|
|
164 |
|
|
/* Note: we are allowed to modify line */ |
165 |
|
|
static void |
166 |
|
|
keylist_colon_handler( gpgme_ctx_t ctx, char * line ) |
167 |
|
|
{ |
168 |
|
|
enum { |
169 |
|
|
RT_NONE, |
170 |
|
|
RT_SIG, |
171 |
|
|
RT_UID, |
172 |
|
|
RT_SUB, |
173 |
|
|
RT_PUB, |
174 |
|
|
RT_FPR, |
175 |
|
|
RT_SSB, |
176 |
|
|
RT_SEC, |
177 |
|
|
RT_PKD, |
178 |
|
|
} rectype = RT_NONE; |
179 |
|
|
gpgme_key_t key = ctx->tmp_key; |
180 |
|
|
struct subkey_s * sk = NULL; |
181 |
|
|
struct signature_s * sig = NULL; |
182 |
|
|
struct subkey_s * s = NULL; |
183 |
|
|
struct user_id_s * u = NULL; |
184 |
|
|
struct mpi_s * m = NULL, * mt = NULL; |
185 |
|
|
const char * trust_info = NULL; |
186 |
|
|
char * p, * pend; |
187 |
|
|
int field = 0; |
188 |
|
|
unsigned long val=0; |
189 |
|
|
int i; |
190 |
|
|
|
191 |
|
|
if( ctx->out_of_core ) |
192 |
|
|
return; |
193 |
|
|
if( !line ) { /* EOF */ |
194 |
|
|
if( ctx->tmp_key ) |
195 |
|
|
finish_key( ctx ); |
196 |
|
|
return; |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
for( p = line; p; p = pend ) { |
200 |
|
|
field++; |
201 |
|
|
pend = strchr( p, ':' ); |
202 |
|
|
if( pend ) |
203 |
|
|
*pend++ = 0; |
204 |
|
|
|
205 |
|
|
if( field == 1 ) { |
206 |
|
|
if( !strcmp( p, "sig" ) && key ) { |
207 |
|
|
rectype = RT_SIG; |
208 |
|
|
sig = _gpgme_key_add_signature( key ); |
209 |
|
|
if( !sig ) { |
210 |
|
|
ctx->out_of_core = 1; |
211 |
|
|
break; |
212 |
|
|
} |
213 |
|
|
} |
214 |
|
|
else if( !strcmp( p, "uid" ) && key ) { |
215 |
|
|
rectype = RT_UID; |
216 |
|
|
key = ctx->tmp_key; |
217 |
|
|
sig = _gpgme_key_add_signature( key ); |
218 |
|
|
if( !sig ) { |
219 |
|
|
ctx->out_of_core = 1; |
220 |
|
|
break; |
221 |
|
|
} |
222 |
|
|
} |
223 |
|
|
else if( !strcmp( p, "sub" ) && key ) { |
224 |
|
|
/* start a new subkey */ |
225 |
|
|
rectype = RT_SUB; |
226 |
|
|
sk = _gpgme_key_add_subkey( key ); |
227 |
|
|
if( !sk ) { |
228 |
|
|
ctx->out_of_core = 1; |
229 |
|
|
return; |
230 |
|
|
} |
231 |
|
|
} |
232 |
|
|
else if( !strcmp( p, "ssb" ) && key ) { |
233 |
|
|
/* start a new secret subkey */ |
234 |
|
|
rectype = RT_SSB; |
235 |
|
|
sk = _gpgme_key_add_secret_subkey( key ); |
236 |
|
|
if( !sk ) { |
237 |
|
|
ctx->out_of_core = 1; |
238 |
|
|
return; |
239 |
|
|
} |
240 |
|
|
} |
241 |
|
|
else if( !strcmp( p, "pub" ) ) { |
242 |
|
|
/* start a new keyblock */ |
243 |
|
|
if( _gpgme_key_new ( &key ) ) { |
244 |
|
|
ctx->out_of_core = 1; /* the only kind of error we can get*/ |
245 |
|
|
return; |
246 |
|
|
} |
247 |
|
|
rectype = RT_PUB; |
248 |
|
|
if ( ctx->tmp_key ) |
249 |
|
|
finish_key ( ctx ); |
250 |
|
|
assert ( !ctx->tmp_key ); |
251 |
|
|
ctx->tmp_key = key; |
252 |
|
|
ctx->tmp_i = 0; |
253 |
|
|
if (ctx->cb.progress) |
254 |
|
|
ctx->cb.progress (ctx->cb.progress_value, "keylist", 0, |
255 |
|
|
ctx->cb.progess_tmp, |
256 |
|
|
ctx->cb.progress_value_int); |
257 |
|
|
ctx->cb.progess_tmp++; |
258 |
|
|
} |
259 |
|
|
else if( !strcmp ( p, "sec" ) ) { |
260 |
|
|
/* start a new keyblock */ |
261 |
|
|
if ( _gpgme_key_new_secret( &key ) ) { |
262 |
|
|
ctx->out_of_core = 1; /* the only kind of error we can get */ |
263 |
|
|
return; |
264 |
|
|
} |
265 |
|
|
rectype = RT_SEC; |
266 |
|
|
if( ctx->tmp_key ) |
267 |
|
|
finish_key ( ctx ); |
268 |
|
|
assert ( !ctx->tmp_key ); |
269 |
|
|
ctx->tmp_key = key; |
270 |
|
|
} |
271 |
|
|
else if( !strcmp( p, "fpr" ) && key ) |
272 |
|
|
rectype = RT_FPR; |
273 |
|
|
else if( !strcmp( p, "pkd" ) && key ) |
274 |
|
|
rectype = RT_PKD; |
275 |
|
|
else |
276 |
|
|
rectype = RT_NONE; |
277 |
|
|
} |
278 |
|
|
else if( rectype == RT_PUB || rectype == RT_SEC ) |
279 |
|
|
{ |
280 |
|
|
switch( field ) { |
281 |
|
|
case 2: /* trust info */ |
282 |
|
|
trust_info = p; |
283 |
|
|
set_mainkey_trust_info( key, trust_info ); |
284 |
|
|
break; |
285 |
|
|
case 3: /* key length */ |
286 |
|
|
i = atoi( p ); |
287 |
|
|
if( i > 1 ) /* ignore invalid values */ |
288 |
|
|
key->keys.key_len = i; |
289 |
|
|
break; |
290 |
|
|
case 4: /* pubkey algo */ |
291 |
|
|
i = atoi ( p ); |
292 |
|
|
if( i > 0 && i < 128 ) |
293 |
|
|
key->keys.key_algo = i; |
294 |
|
|
break; |
295 |
|
|
case 5: /* long keyid */ |
296 |
|
|
memset (key->keys.keyid, 0, sizeof key->keys.keyid); |
297 |
|
|
strncpy (key->keys.keyid, p, DIM (key->keys.keyid)-1); |
298 |
|
|
break; |
299 |
|
|
case 6: /* timestamp (1998-02-28) */ |
300 |
|
|
key->keys.timestamp = parse_timestamp( p ); |
301 |
|
|
break; |
302 |
|
|
case 7: /* valid for n days */ |
303 |
|
|
key->keys.expires = parse_timestamp( p ); |
304 |
|
|
break; |
305 |
|
|
case 8: /* reserved (LID) */ |
306 |
|
|
break; |
307 |
|
|
case 9: /* ownertrust */ |
308 |
|
|
set_mainkey_ownertrust( key, p ); |
309 |
|
|
break; |
310 |
|
|
case 10: /* not used due to --fixed-list-mode option */ |
311 |
|
|
break; |
312 |
|
|
case 11: /* signature class */ |
313 |
|
|
break; |
314 |
|
|
case 12: /* capabilities */ |
315 |
|
|
set_mainkey_capability( key, p ); |
316 |
|
|
break; |
317 |
|
|
case 15: |
318 |
|
|
if (p && * p) |
319 |
|
|
{ |
320 |
|
|
key->gloflags.divert_to_card = 1; |
321 |
|
|
memset (key->keys.cardno, 0, sizeof key->keys.cardno); |
322 |
|
|
strncpy (key->keys.cardno, p, DIM (key->keys.cardno)); |
323 |
|
|
} |
324 |
|
|
pend = NULL; /* we can stop here */ |
325 |
|
|
break; |
326 |
|
|
} |
327 |
|
|
} |
328 |
|
|
else if( (rectype == RT_SUB || rectype== RT_SSB) && sk ) { |
329 |
|
|
switch( field ) { |
330 |
|
|
case 2: /* trust info */ |
331 |
|
|
set_subkey_trust_info( sk, p ); |
332 |
|
|
break; |
333 |
|
|
case 3: /* key length */ |
334 |
|
|
i = atoi( p ); |
335 |
|
|
if ( i > 1 ) /* ignore invalid values */ |
336 |
|
|
sk->key_len = i; |
337 |
|
|
break; |
338 |
|
|
case 4: /* pubkey algo */ |
339 |
|
|
i = atoi( p ); |
340 |
|
|
if( i > 0 && i < 128 ) |
341 |
|
|
sk->key_algo = i; |
342 |
|
|
break; |
343 |
|
|
case 5: /* long keyid */ |
344 |
|
|
memset (sk->keyid, 0, sizeof sk->keyid); |
345 |
|
|
strncpy (sk->keyid, p, DIM (sk->keyid)-1); |
346 |
|
|
break; |
347 |
|
|
case 6: /* timestamp (1998-02-28) */ |
348 |
|
|
sk->timestamp = parse_timestamp( p ); |
349 |
|
|
break; |
350 |
|
|
case 7: /* valid for n days */ |
351 |
|
|
sk->expires = parse_timestamp( p ); |
352 |
|
|
break; |
353 |
|
|
case 8: /* reserved (LID) */ |
354 |
|
|
break; |
355 |
|
|
case 9: /* ownertrust */ |
356 |
|
|
break; |
357 |
|
|
case 10:/* user ID n/a for a subkey */ |
358 |
|
|
break; |
359 |
|
|
case 11: /* signature class */ |
360 |
|
|
break; |
361 |
|
|
case 12: /* capability */ |
362 |
|
|
set_subkey_capability ( sk, p ); |
363 |
|
|
break; |
364 |
|
|
case 15: |
365 |
|
|
memset (sk->cardno, 0, sizeof sk->cardno); |
366 |
|
|
strncpy (sk->cardno, p, DIM (sk->cardno)-1); |
367 |
|
|
pend = NULL; /* we can stop here */ |
368 |
|
|
break; |
369 |
|
|
} |
370 |
|
|
} |
371 |
|
|
else if (rectype == RT_UID) |
372 |
|
|
{ |
373 |
|
|
switch (field) |
374 |
|
|
{ |
375 |
|
|
case 2: /* trust info */ |
376 |
|
|
trust_info = p; /* save for later use */ |
377 |
|
|
break; |
378 |
|
|
case 6: /* creation date */ |
379 |
|
|
if (p) |
380 |
|
|
val = parse_timestamp (p); |
381 |
|
|
break; |
382 |
|
|
|
383 |
|
|
case 8: /* hash over name */ |
384 |
|
|
break; |
385 |
|
|
|
386 |
|
|
case 10: /* user ID */ |
387 |
|
|
safe_free (ctx->tmp_id); |
388 |
|
|
ctx->tmp_id = strdup (p); |
389 |
|
|
if (!ctx->tmp_id) { |
390 |
|
|
ctx->out_of_core = 1; |
391 |
|
|
break; |
392 |
|
|
} |
393 |
|
|
if (_gpgme_key_append_name (key, p, &u)) |
394 |
|
|
ctx->out_of_core = 1; |
395 |
|
|
else if (trust_info) |
396 |
|
|
set_userid_flags (u, trust_info); |
397 |
|
|
if (sig) { |
398 |
|
|
safe_free (sig->issuer); |
399 |
|
|
sig->issuer = calloc (1, strlen (p) + 1); |
400 |
|
|
if (!sig->issuer) { |
401 |
|
|
ctx->out_of_core = 1; |
402 |
|
|
break; |
403 |
|
|
} |
404 |
|
|
_gpgme_decode_c_string (p, &sig->issuer, strlen (p)+ 1); |
405 |
|
|
} |
406 |
|
|
u->created = val; |
407 |
|
|
pend = NULL; /* we can stop here */ |
408 |
|
|
break; |
409 |
|
|
} |
410 |
|
|
} |
411 |
|
|
else if( rectype == RT_FPR ) { |
412 |
|
|
int nfpr = ctx->tmp_i; |
413 |
|
|
switch( field ) { |
414 |
|
|
case 10: |
415 |
|
|
for( s = &key->keys; s && nfpr; s = s->next, nfpr-- ) |
416 |
|
|
; |
417 |
|
|
if( s ) { |
418 |
|
|
s->fingerprint = strdup( p ); |
419 |
|
|
if( !s->fingerprint ) { |
420 |
|
|
ctx->out_of_core = 1; |
421 |
|
|
break; |
422 |
|
|
} |
423 |
|
|
} |
424 |
|
|
pend = NULL; /* that is all we want */ |
425 |
|
|
ctx->tmp_i++; |
426 |
|
|
break; |
427 |
|
|
} |
428 |
|
|
} |
429 |
|
|
else if( rectype == RT_SIG ) { |
430 |
|
|
switch( field ) { |
431 |
|
|
case 2: /* signature state */ |
432 |
|
|
switch( *p ) { |
433 |
|
|
case '!': sig->stat = GPGME_SIG_STAT_GOOD; break; |
434 |
|
|
case '-': sig->stat = GPGME_SIG_STAT_BAD; break; |
435 |
|
|
case '?': sig->stat = GPGME_SIG_STAT_NOKEY; break; |
436 |
|
|
case '%': sig->stat = GPGME_SIG_STAT_ERROR; break; |
437 |
|
|
default : sig->stat = GPGME_SIG_STAT_NONE; break; |
438 |
|
|
} |
439 |
|
|
break; |
440 |
|
|
|
441 |
|
|
case 4: /* pk algorithm */ |
442 |
|
|
sig->algo = atol (p); |
443 |
|
|
break; |
444 |
|
|
|
445 |
|
|
case 5: /* long keyid */ |
446 |
|
|
memset (sig->keyid, 0, sizeof sig->keyid); |
447 |
|
|
strncpy (sig->keyid, p, DIM (sig->keyid)-1); |
448 |
|
|
break; |
449 |
|
|
|
450 |
|
|
case 6: /* created */ |
451 |
|
|
sig->created = parse_timestamp( p ); |
452 |
|
|
break; |
453 |
|
|
|
454 |
|
|
case 7: /* expires */ |
455 |
|
|
sig->expires = parse_timestamp( p ); |
456 |
|
|
break; |
457 |
|
|
|
458 |
|
|
case 10: |
459 |
|
|
if( p ) { |
460 |
|
|
sig->issuer = calloc( 1, strlen( p ) + 1 ); |
461 |
|
|
if( !sig->issuer ) { |
462 |
|
|
ctx->out_of_core = 1; |
463 |
|
|
break; |
464 |
|
|
} |
465 |
|
|
_gpgme_decode_c_string( p, &sig->issuer, strlen( p ) + 1 ); |
466 |
|
|
} |
467 |
|
|
break; |
468 |
|
|
|
469 |
|
|
case 11: |
470 |
|
|
sig->sigclass = strtoul( p, NULL, 16 ); |
471 |
|
|
if (strchr (p, 'l')) |
472 |
|
|
sig->is_local = 1; |
473 |
|
|
/*if (strchr (p, ' ')) |
474 |
|
|
sig->is_nonrev = 1;*/ |
475 |
|
|
if (sig->sigclass < 0x10 || sig->sigclass > 0x13) { |
476 |
|
|
/* we only want certificates and no key signatures */ |
477 |
|
|
pend = NULL; |
478 |
|
|
break; |
479 |
|
|
} |
480 |
|
|
if( ctx->tmp_id ) { |
481 |
|
|
sig->user_id = calloc( 1, strlen( ctx->tmp_id ) + 1 ); |
482 |
|
|
if( !sig->user_id ) { |
483 |
|
|
ctx->out_of_core = 1; |
484 |
|
|
break; |
485 |
|
|
} |
486 |
|
|
_gpgme_decode_c_string( ctx->tmp_id, &sig->user_id, strlen( ctx->tmp_id ) +1 ); |
487 |
|
|
} |
488 |
|
|
pend = NULL; /* we can stop here */ |
489 |
|
|
break; |
490 |
|
|
} |
491 |
|
|
} |
492 |
|
|
else if( rectype == RT_PKD ) { |
493 |
|
|
switch( field ) { |
494 |
|
|
case 1: |
495 |
|
|
m = calloc( 1, sizeof * m ); |
496 |
|
|
if( !m ) { |
497 |
|
|
ctx->out_of_core = 1; |
498 |
|
|
return; |
499 |
|
|
} |
500 |
|
|
for( mt=key->pkey; mt->next; mt=mt->next ) |
501 |
|
|
; |
502 |
|
|
mt->next = m; |
503 |
|
|
break; |
504 |
|
|
|
505 |
|
|
case 2: |
506 |
|
|
if( m ) |
507 |
|
|
m->bits = atol( p ); |
508 |
|
|
break; |
509 |
|
|
|
510 |
|
|
case 3: |
511 |
|
|
if( m ) { |
512 |
|
|
m->hexval = strdup( p ); |
513 |
|
|
if( !m->hexval ) |
514 |
|
|
ctx->out_of_core=1; |
515 |
|
|
} |
516 |
|
|
break; |
517 |
|
|
} |
518 |
|
|
} |
519 |
|
|
} |
520 |
|
|
|
521 |
|
|
} |
522 |
|
|
|
523 |
|
|
|
524 |
|
|
/* |
525 |
|
|
* We have read an entire key into ctx->tmp_key and should now finish |
526 |
|
|
* it. It is assumed that this releases ctx->tmp_key. |
527 |
|
|
*/ |
528 |
|
|
static void |
529 |
|
|
finish_key( gpgme_ctx_t ctx ) |
530 |
|
|
{ |
531 |
|
|
gpgme_key_t key = ctx->tmp_key; |
532 |
|
|
struct key_queue_item_s * q, * q2; |
533 |
|
|
|
534 |
|
|
assert( key ); |
535 |
|
|
ctx->tmp_key = NULL; |
536 |
|
|
|
537 |
|
|
q = malloc( sizeof *q ); |
538 |
|
|
if( !q ) { |
539 |
|
|
gpgme_key_release( key ); |
540 |
|
|
ctx->out_of_core = 1; |
541 |
|
|
return; |
542 |
|
|
} |
543 |
|
|
q->key = key; |
544 |
|
|
q->next = NULL; |
545 |
|
|
/* fixme: lock queue. Use a tail pointer? */ |
546 |
|
|
q2 = ctx->key_queue; |
547 |
|
|
if( !q2 ) |
548 |
|
|
ctx->key_queue = q; |
549 |
|
|
else { |
550 |
|
|
for( ; q2->next; q2 = q2->next ) |
551 |
|
|
; |
552 |
|
|
q2->next = q; |
553 |
|
|
} |
554 |
|
|
ctx->key_cond = 1; |
555 |
|
|
/* fixme: unlock queue */ |
556 |
|
|
} |
557 |
|
|
|
558 |
|
|
|
559 |
|
|
|
560 |
|
|
/** |
561 |
|
|
* gpgme_op_keylist_start: |
562 |
|
|
* @c: context |
563 |
|
|
* @pattern: a GnuPg user ID or NULL for all |
564 |
|
|
* @secret_only: List only keys where the secret part is available |
565 |
|
|
* |
566 |
|
|
* Note that this function also cancels a pending key listing operaton.. |
567 |
|
|
* |
568 |
|
|
* Return value: 0 on success or an errorcode. |
569 |
|
|
**/ |
570 |
|
|
gpgme_error_t |
571 |
|
|
gpgme_op_keylist_start( gpgme_ctx_t ctx, const char *pattern, int secret_only ) |
572 |
|
|
{ |
573 |
|
|
gpgme_error_t rc = 0; |
574 |
|
|
|
575 |
|
|
if( !ctx ) |
576 |
|
|
return mk_error( Invalid_Value ); |
577 |
|
|
ctx->pending = 1; |
578 |
|
|
|
579 |
|
|
_gpgme_release_result( ctx ); |
580 |
|
|
ctx->out_of_core = 0; |
581 |
|
|
ctx->cb.progess_tmp = 0; |
582 |
|
|
|
583 |
|
|
_gpgme_gpg_release( &ctx->gpg ); |
584 |
|
|
gpgme_key_release( ctx->tmp_key ); |
585 |
|
|
ctx->tmp_key = NULL; |
586 |
|
|
/* Fixme: release key_queue */ |
587 |
|
|
|
588 |
|
|
rc = _gpgme_gpg_new( &ctx->gpg ); |
589 |
|
|
if( rc ) |
590 |
|
|
goto leave; |
591 |
|
|
|
592 |
|
|
_gpgme_gpg_set_status_handler( ctx->gpg, keylist_status_handler, ctx ); |
593 |
|
|
rc = _gpgme_gpg_set_colon_line_handler( ctx->gpg, keylist_colon_handler, ctx ); |
594 |
|
|
if ( rc ) |
595 |
|
|
goto leave; |
596 |
|
|
|
597 |
|
|
/* build the commandline */ |
598 |
|
|
if (ctx->use_logging) |
599 |
|
|
_gpgme_gpg_set_logging_handler (ctx->gpg, ctx); |
600 |
|
|
_gpgme_gpg_set_list_options (ctx->gpg, ctx->list_opts); |
601 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "--with-colons" ); |
602 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "--fixed-list-mode" ); |
603 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "--with-fingerprint" ); |
604 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "--with-fingerprint" ); /* for the subkey */ |
605 |
|
|
if( ctx->keylist_mode & 1 ) |
606 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "--no-expensive-trust-checks" ); |
607 |
|
|
if( ctx->keylist_mode & 2 ) |
608 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "--with-key-data" ); |
609 |
|
|
if( ctx->keylist_mode & 4 ) |
610 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "--fast-list-mode" ); |
611 |
|
|
if( 1 || !ctx->keylist_mode ) /* XXX: do all combinations make sense? */ |
612 |
|
|
_gpgme_gpg_add_arg( ctx->gpg, "-vvv" ); /* to list and check sigs */ |
613 |
|
|
_gpgme_gpg_add_arg ( ctx->gpg, secret_only? |
614 |
|
|
"--list-secret-keys": /*"--list-keys"*/ "-k" ); |
615 |
|
|
|
616 |
|
|
/* Tell the gpg object about the data */ |
617 |
|
|
_gpgme_gpg_add_arg ( ctx->gpg, "--" ); |
618 |
|
|
if( pattern && *pattern ) |
619 |
|
|
_gpgme_gpg_add_arg ( ctx->gpg, pattern ); |
620 |
|
|
|
621 |
|
|
/* and kick off the process */ |
622 |
|
|
rc = _gpgme_gpg_spawn ( ctx->gpg, ctx ); |
623 |
|
|
|
624 |
|
|
leave: |
625 |
|
|
if( rc ) { |
626 |
|
|
ctx->pending = 0; |
627 |
|
|
_gpgme_gpg_release ( &ctx->gpg ); |
628 |
|
|
} |
629 |
|
|
return rc; |
630 |
|
|
} |
631 |
|
|
|
632 |
|
|
|
633 |
|
|
gpgme_error_t |
634 |
|
|
gpgme_op_keylist_next( gpgme_ctx_t ctx, gpgme_key_t * r_key ) |
635 |
|
|
{ |
636 |
|
|
struct key_queue_item_s * q; |
637 |
|
|
|
638 |
|
|
if( !r_key ) |
639 |
|
|
return mk_error( Invalid_Value ); |
640 |
|
|
*r_key = NULL; |
641 |
|
|
if( !ctx ) |
642 |
|
|
return mk_error( Invalid_Value ); |
643 |
|
|
if( !ctx->pending ) |
644 |
|
|
return mk_error( No_Request ); |
645 |
|
|
if( ctx->out_of_core ) |
646 |
|
|
return mk_error( Out_Of_Core ); |
647 |
|
|
|
648 |
|
|
if( !ctx->key_queue ) { |
649 |
|
|
_gpgme_wait_on_condition( ctx, 1, &ctx->key_cond ); |
650 |
|
|
if ( ctx->out_of_core ) |
651 |
|
|
return mk_error( Out_Of_Core ); |
652 |
|
|
if( !ctx->key_cond ) |
653 |
|
|
return mk_error( EOF ); |
654 |
|
|
ctx->key_cond = 0; |
655 |
|
|
assert ( ctx->key_queue ); |
656 |
|
|
} |
657 |
|
|
q = ctx->key_queue; |
658 |
|
|
ctx->key_queue = q->next; |
659 |
|
|
|
660 |
|
|
*r_key = q->key; |
661 |
twoaday |
17 |
safe_free (q); |
662 |
twoaday |
2 |
return 0; |
663 |
|
|
} |
664 |
twoaday |
17 |
|
665 |
|
|
|
666 |
|
|
gpgme_error_t |
667 |
|
|
gpgme_op_keylist_getkey (int listmode, const char *pattern, gpgme_key_t *r_key) |
668 |
|
|
{ |
669 |
|
|
gpgme_ctx_t listctx; |
670 |
|
|
gpgme_error_t err; |
671 |
|
|
|
672 |
|
|
err = gpgme_new (&listctx); |
673 |
|
|
if (err) |
674 |
|
|
return err; |
675 |
|
|
/*gpgme_control (listctx, GPGME_CTRL_LISTMODE, listctx->keylist_mode);*/ |
676 |
|
|
err = gpgme_op_keylist_start (listctx, pattern, 0); |
677 |
|
|
if (!err) |
678 |
|
|
err = gpgme_op_keylist_next (listctx, r_key); |
679 |
|
|
gpgme_release (listctx); |
680 |
|
|
return err; |
681 |
|
|
} |