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