1 |
/* gpgme.c - My GnuPG Made Easy |
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 <assert.h> |
25 |
#include <windows.h> |
26 |
#include <process.h> |
27 |
|
28 |
#include "util.h" |
29 |
#include "context.h" |
30 |
#include "ops.h" |
31 |
|
32 |
/** |
33 |
* gpgme_new: |
34 |
* @r_ctx: Returns the new context |
35 |
* |
36 |
* Create a new context to be used with most of the other GPGME |
37 |
* functions. Use gpgme_release_contect() to release all resources |
38 |
* |
39 |
* Return value: An error code |
40 |
**/ |
41 |
gpgme_error_t |
42 |
gpgme_new (gpgme_ctx_t * r_ctx) |
43 |
{ |
44 |
gpgme_ctx_t ctx; |
45 |
|
46 |
if (!r_ctx) |
47 |
return mk_error (Invalid_Value); |
48 |
*r_ctx = NULL; |
49 |
ctx = calloc (1, sizeof *ctx); |
50 |
if (!ctx) |
51 |
return mk_error (Out_Of_Core); |
52 |
ctx->keylist_mode |= 8; /* include sigs */ |
53 |
ctx->cipher_algo = GPGME_CIPHER_AES128; |
54 |
ctx->s2k.digest_algo = GPGME_MD_SHA1; |
55 |
ctx->s2k.mode = GPGME_S2K_ITERSALTED; |
56 |
*r_ctx = ctx; |
57 |
return 0; |
58 |
} |
59 |
|
60 |
/** |
61 |
* gpgme_release: |
62 |
* @c: Context to be released. |
63 |
* |
64 |
* Release all resources associated with the given context. |
65 |
**/ |
66 |
void |
67 |
gpgme_release (gpgme_ctx_t ctx) |
68 |
{ |
69 |
if (!ctx) |
70 |
return; |
71 |
_gpgme_gpg_release (&ctx->gpg); |
72 |
_gpgme_release_result (ctx); |
73 |
gpgme_key_release (ctx->tmp_key); |
74 |
gpgme_data_release (ctx->help_data_1); |
75 |
gpgme_data_release (ctx->notation); |
76 |
gpgme_data_release (ctx->logging); |
77 |
gpgme_signers_clear (ctx); |
78 |
safe_free (ctx->signers); |
79 |
safe_free (ctx->keygen_fpr); |
80 |
safe_free (ctx->locusr); |
81 |
safe_free (ctx->comment); |
82 |
/* fixme: release the key_queue */ |
83 |
safe_free (ctx); |
84 |
} /* gpgme_release */ |
85 |
|
86 |
|
87 |
void |
88 |
_gpgme_release_result (gpgme_ctx_t c) |
89 |
{ |
90 |
assert (c); |
91 |
switch (c->result_type) { |
92 |
case RESULT_TYPE_NONE: |
93 |
break; |
94 |
|
95 |
case RESULT_TYPE_EDITKEY: |
96 |
_gpgme_release_editkey_result (c->result.editk); |
97 |
break; |
98 |
|
99 |
case RESULT_TYPE_ENCRYPT: |
100 |
_gpgme_release_encrypt_result( c->result.encrypt ); |
101 |
break; |
102 |
|
103 |
case RESULT_TYPE_VERIFY: |
104 |
_gpgme_release_verify_result (c->result.verify); |
105 |
break; |
106 |
|
107 |
case RESULT_TYPE_DECRYPT: |
108 |
_gpgme_release_decrypt_result (c->result.decrypt); |
109 |
break; |
110 |
|
111 |
case RESULT_TYPE_SIGN: |
112 |
_gpgme_release_sign_result ( c->result.sign ); |
113 |
break; |
114 |
|
115 |
case RESULT_TYPE_SIGN_ENCRYPT: |
116 |
_gpgme_release_sign_encrypt_result( c->result.sign_enc ); |
117 |
break; |
118 |
|
119 |
case RESULT_TYPE_IMPORT: |
120 |
_gpgme_release_import_result( c->result.import ); |
121 |
break; |
122 |
|
123 |
case RESULT_TYPE_SYMENC: |
124 |
_gpgme_release_symenc_result( c->result.symenc ); |
125 |
break; |
126 |
} |
127 |
|
128 |
c->result.verify = NULL; |
129 |
c->result_type = RESULT_TYPE_NONE; |
130 |
} /* _gpgme_release_result */ |
131 |
|
132 |
|
133 |
/** |
134 |
* gpgme_cancel: |
135 |
* @c: the context |
136 |
* |
137 |
* Cancel the current operation. It is not guaranteed that it will work for |
138 |
* all kinds of operations. It is especially useful in a passphrase callback |
139 |
* to stop the system from asking another time for the passphrase. |
140 |
**/ |
141 |
void |
142 |
gpgme_cancel (gpgme_ctx_t c) |
143 |
{ |
144 |
return_if_fail (c); |
145 |
c->cancel = 1; |
146 |
c->pending = 0; |
147 |
} /* gpgme_cancel */ |
148 |
|
149 |
|
150 |
/** |
151 |
* gpgme_get_notation: |
152 |
* @c: the context |
153 |
* |
154 |
* If there is notation data available from the last signature check, this |
155 |
* function may be used to return this notation data as a string. The string |
156 |
* is a represantaton of that data embedded in a %<notation> container. |
157 |
* |
158 |
* Return value: An string or NULL if no notation data is available. |
159 |
**/ |
160 |
char * |
161 |
gpgme_get_notation (gpgme_ctx_t c) |
162 |
{ |
163 |
if (!c || !c->notation) |
164 |
return NULL; |
165 |
return _gpgme_data_get_as_string (c->notation); |
166 |
} /* gpgme_get_notation */ |
167 |
|
168 |
|
169 |
char * |
170 |
gpgme_get_logging (gpgme_ctx_t c) |
171 |
{ |
172 |
if (!c || !c->logging) |
173 |
return NULL; |
174 |
return _gpgme_data_get_as_string (c->logging); |
175 |
} |
176 |
|
177 |
|
178 |
void |
179 |
gpgme_set_comment (gpgme_ctx_t c, const char * text) |
180 |
{ |
181 |
if (!c) |
182 |
return; |
183 |
safe_free (c->comment); |
184 |
c->comment = strdup (text); |
185 |
if (!c->comment) |
186 |
c->out_of_core = 1; |
187 |
} |
188 |
|
189 |
|
190 |
void |
191 |
gpgme_set_homedir (gpgme_ctx_t c, const char *homedir) |
192 |
{ |
193 |
if (!c) |
194 |
return; |
195 |
safe_free (c->homedir); |
196 |
c->homedir = strdup (homedir); |
197 |
if (!c->homedir) |
198 |
c->out_of_core = 1; |
199 |
} |
200 |
|
201 |
|
202 |
/** |
203 |
* gpgme_control: |
204 |
* @c: the context |
205 |
* @cmd: command to set |
206 |
* @val: the value for the command. |
207 |
* |
208 |
* This is a replace for gpgme_set_xxx because in a DLL it's better to |
209 |
* reduce the amount of functions. |
210 |
**/ |
211 |
void * |
212 |
gpgme_control( gpgme_ctx_t c, int cmd, int val ) |
213 |
{ |
214 |
if( !c ) |
215 |
return 0; |
216 |
|
217 |
if( val == -1 ) { |
218 |
switch( cmd ) { |
219 |
case GPGME_CTRL_ARMOR: return (int *)c->use_armor; |
220 |
case GPGME_CTRL_FPR: return c->keygen_fpr; |
221 |
default: return NULL; |
222 |
} |
223 |
} |
224 |
|
225 |
switch( cmd ) { |
226 |
|
227 |
case GPGME_CTRL_S2K: |
228 |
/* Pass S2K options down to GPG (no=0, yes=1) */ |
229 |
c->s2k.used = val; |
230 |
break; |
231 |
|
232 |
case GPGME_CTRL_S2K_MODE: |
233 |
c->s2k.mode = val; |
234 |
break; |
235 |
|
236 |
case GPGME_CTRL_S2K_HASH: |
237 |
c->s2k.digest_algo = val; |
238 |
break; |
239 |
|
240 |
case GPGME_CTRL_TEXTMODE: |
241 |
/* Enable or disable the use of the special textmode. Textmode is for example |
242 |
used for MIME (RFC2015) signatures. */ |
243 |
c->use_textmode = val; |
244 |
break; |
245 |
|
246 |
case GPGME_CTRL_LISTMODE: |
247 |
/* This function changes the default behaviour of the keylisting functions. |
248 |
Defines values for @mode are: %0 = normal, %1 = fast listing without |
249 |
information about key validity. */ |
250 |
c->keylist_mode |= val; |
251 |
break; |
252 |
|
253 |
case GPGME_CTRL_NO_COMPR: |
254 |
c->no_compress = val; |
255 |
c->force_mdc = val == 1? 1 : 0; |
256 |
break; |
257 |
|
258 |
case GPGME_CTRL_CIPHER: |
259 |
if (val == -1) { /* disable it */ |
260 |
c->cipher_algo = -1; |
261 |
break; |
262 |
} |
263 |
if (val < 1 || val > 7) { |
264 |
c->cipher_algo = GPGME_CIPHER_CAST5; |
265 |
break; |
266 |
} |
267 |
c->cipher_algo = val; |
268 |
break; |
269 |
|
270 |
case GPGME_CTRL_TMPFILES: c->use_tmpfiles = val; break; |
271 |
case GPGME_CTRL_WITH_SECRET_KEY: c->with_secret_key = val; break; |
272 |
case GPGME_CTRL_FORCETRUST: c->force_trust = val; break; |
273 |
case GPGME_CTRL_FORCEOPT: c->force_opt = val; break; |
274 |
case GPGME_CTRL_FILE: c->use_file = val; break; |
275 |
case GPGME_CTRL_THROWKEYID: c->use_throwkeyid = val; break; |
276 |
case GPGME_CTRL_ARMOR: c->use_armor = val; break; |
277 |
case GPGME_CTRL_INTERACTIVE: c->use_interactive = val; break; |
278 |
case GPGME_CTRL_PIPEMODE: c->use_pipemode = val; break; |
279 |
case GPGME_CTRL_LOGGING: c->use_logging = val; break; |
280 |
case GPGME_CTRL_CB_VAL: c->cb.progress_value_int = val; break; |
281 |
} |
282 |
|
283 |
return NULL; |
284 |
} |
285 |
|
286 |
/** |
287 |
* gpgme_set_passphrase_cb: |
288 |
* @c: the context |
289 |
* @cb: A callback function |
290 |
* @cb_value: The value passed to the callback function |
291 |
* |
292 |
* This function sets a callback function to be used to pass a passphrase |
293 |
* to gpg. The preferred way to handle this is by using the gpg-agent, but |
294 |
* because that beast is not ready for real use, you can use this passphrase |
295 |
* thing. |
296 |
* |
297 |
* The callback function is defined as: |
298 |
* <literal> |
299 |
* typedef const char *(*gpgme_passphrase_cb_t)(void*cb_value, |
300 |
* const char *desc, |
301 |
* void *r_hd); |
302 |
* </literal> |
303 |
* and called whenever gpgme needs a passphrase. DESC will have a nice |
304 |
* text, to be used to prompt for the passphrase and R_HD is just a parameter |
305 |
* to be used by the callback it self. Becuase the callback returns a const |
306 |
* string, the callback might want to know when it can release resources |
307 |
* assocated with that returned string; gpgme helps here by calling this |
308 |
* passphrase callback with an DESC of %NULL as soon as it does not need |
309 |
* the returned string anymore. The callback function might then choose |
310 |
* to release resources depending on R_HD. |
311 |
* |
312 |
**/ |
313 |
void |
314 |
gpgme_set_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, |
315 |
void * cb_value) |
316 |
{ |
317 |
if (!ctx) |
318 |
return; |
319 |
ctx->cb.passphrase = cb; |
320 |
ctx->cb.passphrase_value = cb_value; |
321 |
} /* gpgme_set_passphrase_cb */ |
322 |
|
323 |
|
324 |
void |
325 |
gpgme_set_interactive_cb (gpgme_ctx_t ctx, gpgme_interactive_cb_t cb, |
326 |
void * cb_value) |
327 |
{ |
328 |
if (!ctx) |
329 |
return; |
330 |
ctx->cb.interactiv = cb; |
331 |
ctx->cb.interactiv_value = cb_value; |
332 |
} /* gpgme_set_inteactive_cb */ |
333 |
|
334 |
|
335 |
/** |
336 |
* gpgme_set_pprogress_cb: |
337 |
* @c: the context |
338 |
* @cb: A callback function |
339 |
* @cb_value: The value passed to the callback function |
340 |
* |
341 |
* This function sets a callback function to be used as a progress indicator. |
342 |
* |
343 |
* The callback function is defined as: |
344 |
* <literal> |
345 |
* typedef void (*gpgme_progress_cb_t) (void * cb_value, |
346 |
* const char * what, int type, |
347 |
* int curretn, int total); |
348 |
* </literal> |
349 |
* For details on the progress events, see the entry for the PROGRESS |
350 |
* status in the file doc/DETAILS of the GnuPG distribution. |
351 |
**/ |
352 |
void |
353 |
gpgme_set_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t cb, |
354 |
void * cb_value) |
355 |
{ |
356 |
if (!ctx) |
357 |
return; |
358 |
ctx->cb.progress = cb; |
359 |
ctx->cb.progress_value = cb_value; |
360 |
} /* gpgme_set_progress_cb */ |
361 |
|
362 |
|
363 |
void |
364 |
gpgme_set_edit_ctx( gpgme_ctx_t ctx, void * edit_ctx, int edit_id ) |
365 |
{ |
366 |
if( !ctx ) |
367 |
return; |
368 |
ctx->edit_opaque = edit_ctx; |
369 |
ctx->edit_cmd = edit_id; |
370 |
} /* gpgme_set_edit_ctx */ |
371 |
|
372 |
|
373 |
void |
374 |
gpgme_set_list_options (gpgme_ctx_t ctx, int optid) |
375 |
{ |
376 |
if (!ctx) |
377 |
return; |
378 |
ctx->list_opts |= optid; |
379 |
} |
380 |
|
381 |
|
382 |
void |
383 |
gpgme_set_cache_ctx (gpgme_ctx_t ctx, void * cache_ctx) |
384 |
{ |
385 |
if( ctx ) |
386 |
ctx->key_lookup = cache_ctx; |
387 |
} /* gpgme_set_cache_ctx */ |
388 |
|
389 |
|
390 |
void |
391 |
gpgme_set_passphrase( gpgme_ctx_t ctx, const char * passphrase ) |
392 |
{ |
393 |
if( !ctx ) |
394 |
return; |
395 |
ctx->passphrase_value = passphrase; |
396 |
ctx->use_pass_fd = 1; |
397 |
} /* gpgme_set_passphrase */ |
398 |
|
399 |
|
400 |
gpgme_error_t |
401 |
_gpgme_add_passphrase( gpgme_ctx_t ctx ) |
402 |
{ |
403 |
gpgme_error_t err; |
404 |
gpgme_data_t passphrase_fd; |
405 |
|
406 |
if( !ctx ) |
407 |
return mk_error( Invalid_Value ); |
408 |
if( !ctx->passphrase_value || !ctx->use_pass_fd ) |
409 |
return mk_error( General_Error ); |
410 |
|
411 |
err = gpgme_data_new_from_mem( &passphrase_fd, ctx->passphrase_value, |
412 |
strlen( ctx->passphrase_value ), 0 ); |
413 |
if( err ) |
414 |
return err; |
415 |
_gpgme_data_set_mode( passphrase_fd, GPGME_DATA_MODE_OUT ); |
416 |
_gpgme_gpg_add_arg( ctx->gpg, "--passphrase-fd" ); |
417 |
_gpgme_gpg_add_data( ctx->gpg, passphrase_fd, -2 ); |
418 |
|
419 |
return 0; |
420 |
} /* _gpgme_add_passphrase */ |
421 |
|
422 |
|
423 |
void |
424 |
gpgme_set_debug_mode( int val ) |
425 |
{ |
426 |
if( val ) |
427 |
putenv( "GPGME_DEBUG=5:gpgme.dbg" ); |
428 |
else |
429 |
putenv( "GPGME_DEBUG=" ); |
430 |
} /* gpgme_set_debug_mode */ |
431 |
|
432 |
|
433 |
const char* |
434 |
_gpgme_get_tmpfile( int input ) |
435 |
{ |
436 |
static char tmpfile[384]; |
437 |
char path[256]; |
438 |
|
439 |
GetTempPath( sizeof path -1, path ); |
440 |
_snprintf( tmpfile, sizeof tmpfile -1, |
441 |
"%sgpgme%s.%u", path, input? "IN" : "OUT", getpid() ); |
442 |
return tmpfile; |
443 |
} /* _gpgme_get_tmpfile */ |
444 |
|
445 |
|
446 |
static int |
447 |
_gpgme_unlink( const char * file, int arg ) |
448 |
{ |
449 |
return unlink( file ); |
450 |
} /* _gpgme_unlink */ |
451 |
|
452 |
|
453 |
void |
454 |
_gpgme_del_tmpfiles( gpgme_wipe_t wipe_fnc ) |
455 |
{ |
456 |
gpgme_wipe_t erase = wipe_fnc? wipe_fnc: (gpgme_wipe_t)_gpgme_unlink; |
457 |
|
458 |
erase( _gpgme_get_tmpfile( 0 ), 1 ); |
459 |
erase( _gpgme_get_tmpfile( 1 ), 1 ); |
460 |
} /* _gpgme_del_tmpfiles */ |
461 |
|
462 |
void |
463 |
gpgme_set_wipe_fnc( gpgme_ctx_t ctx, gpgme_wipe_t fnc ) |
464 |
{ |
465 |
if( ctx ) |
466 |
ctx->wipe_fnc = fnc; |
467 |
} /* gpgme_set_wipe_fnc */ |
468 |
|
469 |
|
470 |
void |
471 |
gpgme_set_local_user( gpgme_ctx_t ctx, const char * name ) |
472 |
{ |
473 |
if( ctx && name ) { |
474 |
safe_free (ctx->locusr); |
475 |
ctx->locusr = strdup( name ); |
476 |
} |
477 |
} /* gpgme_set_local_user */ |
478 |
|
479 |
|
480 |
int |
481 |
gpgme_get_process_rc (gpgme_ctx_t ctx) |
482 |
{ |
483 |
if (!ctx) |
484 |
return -1; |
485 |
return (int)ctx->proc_rc; |
486 |
} /* gpgme_get_process_rc */ |
487 |
|
488 |
|
489 |
void |
490 |
_gpgme_progress_handler (gpgme_ctx_t ctx, char * args) |
491 |
{ |
492 |
const char * name = args; |
493 |
char * buf, * p; |
494 |
char * what = NULL; |
495 |
unsigned curr, total, i=0; |
496 |
|
497 |
/* what */ |
498 |
p = strchr (args, '?'); |
499 |
if (!p) |
500 |
return; |
501 |
what = malloc (p-args+2); |
502 |
if (!what) { |
503 |
ctx->out_of_core = 1; |
504 |
return; |
505 |
} |
506 |
while (name && *name != '?') |
507 |
what[i++] = *name++; |
508 |
what[i] = '\0'; |
509 |
/* XXX remove space at the end */ |
510 |
i = 0; |
511 |
buf = args + (p-args); |
512 |
while ((p = strsep (&buf, " ")) != NULL) { |
513 |
switch (i) { |
514 |
case 0: |
515 |
break; /* type */ |
516 |
case 1: |
517 |
curr = strtoul (p, NULL, 10); |
518 |
break; /* current offset */ |
519 |
case 2: |
520 |
total = strtoul (p, NULL, 10); |
521 |
break; /* total */ |
522 |
} |
523 |
i++; |
524 |
} |
525 |
if (what) { |
526 |
ctx->cb.progress (ctx->cb.progress_value, what, 0, curr, total); |
527 |
safe_free (what); |
528 |
} |
529 |
} /* _gpgme_progress_handler */ |
530 |
|
531 |
|
532 |
void |
533 |
_gpgme_add_comment (gpgme_ctx_t ctx) |
534 |
{ |
535 |
char * p; |
536 |
|
537 |
if (ctx->comment) { |
538 |
p = calloc (1, strlen (ctx->comment)+3); |
539 |
if (!p) { |
540 |
ctx->out_of_core = 1; |
541 |
return; |
542 |
} |
543 |
_gpgme_gpg_add_arg (ctx->gpg, "--comment"); |
544 |
p[0] = '"'; |
545 |
strcpy (p+1, ctx->comment); |
546 |
strcat (p, "\""); |
547 |
_gpgme_gpg_add_arg (ctx->gpg, p); |
548 |
safe_free (p); |
549 |
} |
550 |
} |
551 |
|
552 |
|
553 |
gpgme_error_t |
554 |
gpgme_check_logging (gpgme_ctx_t ctx) |
555 |
{ |
556 |
char * buf; |
557 |
|
558 |
if (!ctx) |
559 |
return mk_error (Invalid_Value); |
560 |
buf = gpgme_get_logging (ctx); |
561 |
if (!buf) |
562 |
return mk_error (No_Error); |
563 |
|
564 |
/* XXX: this only works for English GPG output!!! */ |
565 |
if (strstr (buf, "gpg.conf:") && strstr (buf, "invalid option")) |
566 |
return mk_error (Conf_InvOption); |
567 |
|
568 |
free (buf); |
569 |
return 0; |
570 |
} |
571 |
|
572 |
|
573 |
gpgme_error_t |
574 |
gpgme_lib_init (void) |
575 |
{ |
576 |
return 0; |
577 |
} |
578 |
|
579 |
|
580 |
void |
581 |
gpgme_lib_cleanup (void) |
582 |
{ |
583 |
debug_cleanup (); |
584 |
rungpg_cleanup (); |
585 |
io_cleanup (); |
586 |
wait_cleanup (); |
587 |
util_cleanup (); |
588 |
} |