/[winpt]/trunk/MyGPGME/import.c
ViewVC logotype

Contents of /trunk/MyGPGME/import.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Mon Apr 4 07:01:43 2005 UTC (19 years, 10 months ago) by twoaday
File MIME type: text/plain
File size: 15227 byte(s)
2005-03-22  Timo Schulz  <twoaday@freakmail.de>
                                                                                
        * editcard.c: Support new status-fd entries SC_OP_SUCCESS
        and SC_OP_FAILURE.
        * editkey.c (cmd_addrev_handler): Check if context != NULL.
        * import.c (import_command_handler): Wrong function signature.
        Noted by Kurt Fitzner.
        * types.h: Fixed encrypt_result_s. Noted by Kurt.
        * gpgme.h (gpgme_editkey_addrev_set): Changed return type.
        Kudos to Kurt.
        * key.c: Removed some unreachable code. By Kurt.
                                                                                


1 /* import.c - import functions
2 * Copyright (C) 2000 Werner Koch (dd9jn)
3 * Copyright (C) 2001-2004 Timo Schulz
4 *
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 <assert.h>
26 #include <ctype.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31 #include "key.h"
32
33
34 struct import_result_s {
35 gpgme_recipients_t keys;
36 int import_res[14];
37 int imported;
38 };
39
40
41 void
42 _gpgme_release_import_result( _import_result_t res )
43 {
44 if( res ) {
45 gpgme_recipients_release( res->keys );
46 res->keys = NULL;
47 safe_free( res );
48 }
49 } /* _gpgme_release_import_result */
50
51
52 gpgme_error_t
53 gpgme_get_import_status (gpgme_ctx_t ctx, int * import_res,
54 gpgme_recipients_t * r_keys )
55 {
56 gpgme_recipients_t k;
57 struct user_id_s * s;
58 int i;
59
60 if (!ctx)
61 return mk_error( Invalid_Value );
62
63 assert( ctx->result_type == RESULT_TYPE_IMPORT );
64 for (i = 0; i < 14; i++)
65 import_res[i] = ctx->result.import->import_res[i];
66 if (r_keys && ctx->result.import->keys) {
67 if (gpgme_recipients_new (&k))
68 return mk_error (Out_Of_Core);
69 for (s=ctx->result.import->keys->list; s; s=s->next)
70 gpgme_recipients_add_name (k, s->name);
71 *r_keys = k;
72 }
73 return 0;
74 } /* gpgme_get_import_status */
75
76
77
78 static const char *
79 import_command_handler (void *opaque, gpg_status_code_t code, const char * key)
80 {
81 gpgme_ctx_t ctx = opaque;
82 struct user_id_s * r;
83
84 if (code != STATUS_GET_BOOL)
85 return NULL;
86
87 /* We can use the interactive mode to get a summary of the imported
88 keys. We always say YES in this case because the IMPORT_CHECK
89 contains the user-id and this might be useful */
90 if (!ctx->enc_to)
91 return "Y";
92
93 for (r = ctx->enc_to->list; r; r = r->next) {
94 if (!strncmp (r->name, ctx->tmp_keyid+8, 8)) {
95 DEBUG1 ("interactive import `%s´: ok\n", ctx->tmp_keyid+8);
96 return "Y";
97 }
98 }
99 return "N";
100 } /* import_command_handler */
101
102
103 static void
104 import_status_handler (gpgme_ctx_t ctx, gpg_status_code_t code, char * args)
105 {
106 const char * s;
107
108 if (ctx->out_of_core)
109 return;
110
111 if( ctx->result_type == RESULT_TYPE_NONE ) {
112 assert ( !ctx->result.import );
113 ctx->result.import = calloc( 1, sizeof *ctx->result.import );
114 if( !ctx->result.import ) {
115 ctx->out_of_core = 1;
116 return;
117 }
118 ctx->result.import->imported = 0;
119 ctx->result_type = RESULT_TYPE_IMPORT;
120 }
121
122 switch (code) {
123 case STATUS_NODATA:
124 ctx->result.import->imported = -1;
125 break;
126
127 case STATUS_IMPORT_CHECK:
128 if (!ctx->result.import->keys)
129 gpgme_recipients_new (&ctx->result.import->keys);
130 s = args;
131 while (s && *s != ' ')
132 s++;
133 s++;
134 while (s && *s != ' ')
135 s++;
136 s++;
137 gpgme_recipients_add_name (ctx->result.import->keys, s);
138 strncpy (ctx->tmp_keyid, args, 16);
139 break;
140
141 case STATUS_IMPORTED:
142 ctx->result.import->imported++;
143 break;
144
145 case STATUS_IMPORT_RES:
146 /* IMPORT_RES <count> <no_user_id> <imported> <imported_rsa>
147 <unchanged> <n_uids> <n_subk> <n_sigs> <n_revoc>
148 <sec_read> <sec_imported> <sec_dups> <not_imported> */
149 ctx->result.import->imported++;
150 sscanf (args, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d",
151 &ctx->result.import->import_res[ 0],
152 &ctx->result.import->import_res[ 1],
153 &ctx->result.import->import_res[ 2],
154 &ctx->result.import->import_res[ 3],
155 &ctx->result.import->import_res[ 4],
156 &ctx->result.import->import_res[ 5],
157 &ctx->result.import->import_res[ 6],
158 &ctx->result.import->import_res[ 7],
159 &ctx->result.import->import_res[ 8],
160 &ctx->result.import->import_res[ 9],
161 &ctx->result.import->import_res[10],
162 &ctx->result.import->import_res[11],
163 &ctx->result.import->import_res[12],
164 &ctx->result.import->import_res[13]);
165 /* we add the RSA keys to have one sum. we don't need to differ
166 between RSA and other keys after the patent has been expired. */
167 ctx->result.import->import_res[2] += ctx->result.import->import_res[3];
168 break;
169 }
170 } /* import_status_handler */
171
172
173 static gpgme_error_t
174 import_start( gpgme_ctx_t ctx, gpgme_data_t keydata )
175 {
176 gpgme_error_t rc = 0;
177
178 fail_on_pending_request( ctx );
179 ctx->pending = 1;
180
181 /* create a process object */
182 _gpgme_gpg_release( &ctx->gpg );
183 rc = _gpgme_gpg_new( &ctx->gpg );
184 if( rc )
185 goto leave;
186
187 if( ctx->interactive )
188 _gpgme_gpg_set_command_handler( ctx->gpg, import_command_handler, ctx );
189 if( ctx->use_logging )
190 _gpgme_gpg_set_logging_handler( ctx->gpg, ctx );
191 _gpgme_gpg_set_status_handler( ctx->gpg, import_status_handler, ctx );
192
193 /* build the commandline */
194 if( ctx->force_opt )
195 _gpgme_gpg_add_arg( ctx->gpg, "--allow-non-selfsigned-uid" );
196 _gpgme_gpg_add_arg( ctx->gpg, "--allow-secret-key-import" );
197 if( ctx->interactive )
198 _gpgme_gpg_add_arg( ctx->gpg, "--interactive" );
199 _gpgme_gpg_add_arg ( ctx->gpg, "--import" );
200
201 /* Check the supplied data */
202 if( gpgme_data_get_type( keydata ) == GPGME_DATA_TYPE_NONE ) {
203 rc = mk_error( No_Data );
204 goto leave;
205 }
206 _gpgme_data_set_mode( keydata, GPGME_DATA_MODE_OUT );
207 _gpgme_gpg_add_data( ctx->gpg, keydata, 0 );
208 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
209
210 leave:
211 if( rc ) {
212 ctx->pending = 0;
213 _gpgme_gpg_release ( &ctx->gpg );
214 }
215 return rc;
216 } /* import_start */
217
218
219 static gpgme_error_t
220 file_import_start( gpgme_ctx_t ctx, const char *input )
221 {
222 gpgme_error_t rc;
223
224 if( !ctx )
225 return mk_error( Invalid_Value );
226
227 fail_on_pending_request( ctx );
228 ctx->pending = 1;
229
230 _gpgme_gpg_release( &ctx->gpg );
231 rc = _gpgme_gpg_new( &ctx->gpg );
232 if( rc )
233 return rc;
234
235 if( ctx->interactive )
236 _gpgme_gpg_set_command_handler( ctx->gpg, import_command_handler, ctx );
237 _gpgme_gpg_set_status_handler( ctx->gpg, import_status_handler, ctx );
238 if( ctx->interactive )
239 _gpgme_gpg_add_arg( ctx->gpg, "--interactive" );
240 _gpgme_gpg_add_arg( ctx->gpg, "--yes" );
241 _gpgme_gpg_add_arg( ctx->gpg, "--allow-non-selfsigned-uid" );
242 _gpgme_gpg_add_arg( ctx->gpg, "--allow-secret-key-import" );
243 _gpgme_gpg_add_arg( ctx->gpg, "--import" );
244 _gpgme_gpg_add_arg( ctx->gpg, input );
245
246 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
247 if( rc ) {
248 ctx->pending = 0;
249 _gpgme_gpg_release( &ctx->gpg );
250 }
251
252 return rc;
253 } /* file_import_start */
254
255
256 static gpgme_error_t
257 get_import_result( gpgme_ctx_t ctx )
258 {
259 gpgme_error_t err = 0;
260
261 if( ctx->result_type != RESULT_TYPE_IMPORT )
262 err = mk_error( General_Error );
263 else if( ctx->out_of_core )
264 err = mk_error( Out_Of_Core );
265 else {
266 assert( ctx->result.import );
267 if( ctx->result.import->imported == -1 )
268 err = mk_error( No_Data );
269 else if( !ctx->result.import->imported )
270 err = mk_error( General_Error );
271 else if( gpgme_get_process_rc( ctx ) == 2
272 && ctx->result.import->import_res[GPGME_IMPSTAT_NSKEYS] ) {
273 /* GPG isssues a warning when the secret key is already
274 in the secret keyring. Due to the fact GPG can't merge
275 secret keys, the return code is incremented but this
276 is in fact no real error. */
277 err = 0;
278 }
279 else if( gpgme_get_process_rc( ctx ) )
280 err = mk_error( Internal_GPG_Problem );
281 }
282
283 return err;
284 } /* get_import_result */
285
286
287 gpgme_error_t
288 gpgme_op_import( gpgme_ctx_t ctx, gpgme_recipients_t selkeys, gpgme_data_t keydata )
289 {
290 gpgme_error_t err;
291
292 ctx->enc_to = selkeys;
293 err = import_start( ctx, keydata );
294 if( !err ) {
295 gpgme_wait( ctx, 1 );
296 ctx->pending = 0;
297 err = get_import_result( ctx );
298 }
299
300 return err;
301 } /* gpgme_op_import */
302
303
304 gpgme_error_t
305 gpgme_op_file_import( gpgme_ctx_t ctx, gpgme_recipients_t selkeys, const char *input )
306 {
307 gpgme_error_t err;
308
309 ctx->enc_to = selkeys;
310 err = file_import_start( ctx, input );
311 if( !err ) {
312 gpgme_wait( ctx, 1 );
313 ctx->pending = 0;
314 err = get_import_result( ctx );
315 }
316
317 return err;
318 } /* gpgme_op_file_import */
319
320
321 gpgme_error_t
322 gpgme_op_clip_import (int ctrl, gpgme_recipients_t selkeys, int * import_res)
323 {
324 gpgme_error_t err = 0;
325 gpgme_ctx_t ctx = NULL;
326 gpgme_data_t keydata = NULL;
327
328 err = gpgme_new (&ctx);
329 if (err)
330 return err;
331 if( ctrl & GPGME_CTRL_FORCEOPT )
332 gpgme_control( ctx, GPGME_CTRL_FORCEOPT, 1 );
333 err = gpgme_data_new_from_clipboard (&keydata);
334 if( !err )
335 err = gpgme_op_import( ctx, selkeys, keydata );
336 if( !err )
337 err = gpgme_get_import_status( ctx, import_res, NULL );
338
339 gpgme_data_release( keydata );
340 gpgme_release( ctx );
341
342 return err;
343 } /* gpgme_op_clip_import */
344
345
346 static gpgme_error_t
347 import_list_start( gpgme_ctx_t ctx, gpgme_data_t in, gpgme_data_t out )
348 {
349 gpgme_error_t rc;
350
351 fail_on_pending_request( ctx );
352 ctx->pending = 1;
353
354 _gpgme_gpg_release( &ctx->gpg );
355 rc = _gpgme_gpg_new( &ctx->gpg );
356 if( rc )
357 goto leave;
358
359 /*_gpgme_gpg_add_arg( ctx->gpg, "--fast-list-mode" );*/
360 _gpgme_gpg_add_arg( ctx->gpg, "--fixed-list-mode" );
361 _gpgme_gpg_add_arg( ctx->gpg, "--with-colons" );
362
363 if( gpgme_data_get_type( in ) == GPGME_DATA_TYPE_NONE ) {
364 rc = mk_error( No_Data );
365 goto leave;
366 }
367
368 _gpgme_data_set_mode( in, GPGME_DATA_MODE_OUT );
369 _gpgme_data_set_mode( out, GPGME_DATA_MODE_IN );
370
371 _gpgme_gpg_add_arg( ctx->gpg, "--output" );
372 _gpgme_gpg_add_arg( ctx->gpg, "-" );
373 _gpgme_gpg_add_data( ctx->gpg, out, 1 );
374 _gpgme_gpg_add_arg( ctx->gpg, "--" );
375 _gpgme_gpg_add_data( ctx->gpg, in, 0 );
376
377 rc = _gpgme_gpg_spawn( ctx->gpg, ctx );
378
379 leave:
380 if( rc ) {
381 ctx->pending = 0;
382 _gpgme_gpg_release( &ctx->gpg );
383 }
384
385 return rc;
386 } /* import_list_start */
387
388
389 gpgme_error_t
390 gpgme_op_import_list( gpgme_ctx_t ctx, gpgme_data_t in, gpgme_data_t out )
391 {
392 gpgme_error_t err;
393
394 err = import_list_start( ctx, in, out );
395 if( !err ) {
396 gpgme_wait( ctx, 1 );
397 ctx->pending = 0;
398 if (gpgme_data_get_type (out) == GPGME_DATA_TYPE_NONE)
399 err = mk_error (General_Error);
400 else if (gpgme_get_process_rc (ctx))
401 err = mk_error (Internal_GPG_Problem);
402 }
403
404 return err;
405 } /* gpgme_op_import_list */
406
407
408 static void
409 decode_userid( char * pend, gpgme_key_t c )
410 {
411 char * tmp;
412
413 c->uids = calloc( 1, sizeof *c->uids + strlen( pend ) + 1 );
414 if( !c->uids )
415 return;
416 tmp = c->uids->name;
417 _gpgme_decode_c_string( pend, &tmp, strlen( pend ) + 1 );
418 c->uids->name[strlen( c->uids->name ) -3] = '\0';
419 } /* decode_userid */
420
421
422 static void
423 parse_colon_key( char *buf, gpgme_key_t c )
424 {
425 const char * s;
426 char *p, *pend;
427 int field = 0, rectype = 0;
428 struct subkey_s * subk;
429 enum {
430 KEY_none = 0,
431 KEY_primary = 1,
432 KEY_secondary = 2,
433 };
434
435 if( !buf )
436 return; /* EOF */
437
438 if( !strncmp( buf, "pub", 3 ) || !strncmp( buf, "sec", 3 ) ) {
439 rectype = KEY_primary;
440 if( *buf == 's' )
441 c->secret = 1;
442 }
443 else if( !strncmp( buf, "sub", 3 ) || !strncmp( buf, "ssb", 3 ) ) {
444 rectype = KEY_secondary;
445 if( !c->keys.next )
446 c->keys.next = subk = calloc( 1, sizeof *subk );
447 else
448 subk = c->keys.next;
449 }
450 else if( !strncmp( buf, "uid", 3 ) ) {
451 if( !c->uids ) {
452 const char * s = buf;
453 s += 3;
454 while( s && *s == ':' )
455 s++;
456 decode_userid( (char *)s, c );
457
458 }
459 return;
460 }
461 else
462 return;
463
464 for( p = buf; p; p = pend ) {
465 field++;
466 pend = strchr( p, ':' );
467 if( pend )
468 *pend++ = 0;
469
470 switch( field ) {
471 case 1:
472 if( rectype != KEY_primary )
473 break;
474 for( s = pend; *s && !isdigit( *s ); s++ ) {
475 switch( *s ) {
476 case 'd': c->keys.flags.disabled = 1; break;
477 case 'e': c->keys.flags.expired = 1; break;
478 case 'r': c->keys.flags.revoked = 1; break;
479 }
480 }
481 break;
482
483 case 2:
484 if( rectype == KEY_primary )
485 c->keys.key_len = atoi( pend );
486 else
487 subk->key_len = atoi( pend );
488 break;
489
490 case 3:
491 if( rectype == KEY_primary )
492 c->keys.key_algo = atoi( pend );
493 else
494 subk->key_algo = atoi( pend );
495 break;
496
497 case 4:
498 if( rectype == KEY_primary ) {
499 memcpy( c->keys.keyid, pend, 16 );
500 c->keys.keyid[16] = '\0';
501 }
502 else {
503 memcpy( subk->keyid, pend, 16 );
504 subk->keyid[16]= '\0';
505 }
506 break;
507
508 case 5:
509 if( rectype == KEY_primary )
510 c->keys.timestamp = strtoul( pend, NULL, 10 );
511 else
512 subk->timestamp = strtoul( pend, NULL, 10 );
513 break;
514
515 case 9:
516 if( rectype == KEY_primary && !c->uids && strlen( pend ) > 2 ) {
517 if( !strchr( pend, '[' ) && !strchr( pend, ']' ) )
518 decode_userid( pend, c );
519 }
520 break;
521 }
522 }
523 } /* parse_colon_key */
524
525
526 gpgme_error_t
527 gpgme_op_import_list_next( gpgme_data_t out, char **pending_line, gpgme_key_t *r_key )
528 {
529 gpgme_key_t key = NULL;
530 int in_cert, got_block = 0;
531 char buf[384];
532
533 if( !r_key )
534 return mk_error( Invalid_Value );
535
536 if( _gpgme_key_new( &key ) )
537 return mk_error( Out_Of_Core );
538
539 if( *pending_line ) {
540 parse_colon_key( *pending_line, key );
541 safe_free( *pending_line );
542 *pending_line = NULL;
543 in_cert = 1;
544 }
545 else
546 in_cert = 0;
547
548 while( gpgme_data_readline( out, buf, sizeof buf-1 ) ) {
549 if( !strncmp( buf, "pub", 3 )
550 || !strncmp( buf, "sec", 3 ) ) {
551 if( in_cert ) {
552 *pending_line = strdup( buf );
553 goto ready;
554 }
555 in_cert = 1, got_block = 1;
556 parse_colon_key( buf, key );
557 }
558 else if( in_cert ) {
559 parse_colon_key( buf, key );
560 got_block = 1;
561 }
562 }
563 ready:
564 *r_key = key;
565 if( got_block && _gpgme_data_eof( out ) )
566 return 0;
567 return _gpgme_data_eof( out ) ? mk_error( EOF ) : 0;
568 } /* gpgme_op_import_list_next */

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26