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

Contents of /trunk/MyGPGME/import.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Fri Sep 30 10:10:16 2005 UTC (19 years, 5 months ago) by twoaday
File MIME type: text/plain
File size: 15690 byte(s)
Almost finished phase 1 of the WinPT GPGME port.
Still need more cleanup, comments and tests.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26