2006-06-15 [colin] 2.3.0cvs16
[claws.git] / src / plugins / pgpcore / sgpgme.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2006 Hiroyuki Yamamoto & the Sylpheed-Claws team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19  
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23  
24 #ifdef USE_GPGME
25
26 #include <time.h>
27 #include <gtk/gtk.h>
28 #include <gpgme.h>
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #if HAVE_LOCALE_H
34 #  include <locale.h>
35 #endif
36
37 #include "sgpgme.h"
38 #include "privacy.h"
39 #include "prefs_common.h"
40 #include "utils.h"
41 #include "alertpanel.h"
42 #include "passphrase.h"
43 #include "prefs_gpg.h"
44 #include "select-keys.h"
45
46 static void sgpgme_disable_all(void)
47 {
48     /* FIXME: set a flag, so that we don't bother the user with failed
49      * gpgme messages */
50 }
51
52 gpgme_verify_result_t sgpgme_verify_signature(gpgme_ctx_t ctx, gpgme_data_t sig, 
53                                         gpgme_data_t plain, gpgme_data_t dummy)
54 {
55         gpgme_verify_result_t status = NULL;
56         gpgme_error_t err;
57
58         if ((err = gpgme_op_verify(ctx, sig, plain, dummy)) != GPG_ERR_NO_ERROR) {
59                 debug_print("op_verify err %s\n", gpgme_strerror(err));
60                 privacy_set_error(gpgme_strerror(err));
61                 return GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR);
62                 
63         }
64         status = gpgme_op_verify_result(ctx);
65
66         return status;
67 }
68
69 SignatureStatus sgpgme_sigstat_gpgme_to_privacy(gpgme_ctx_t ctx, gpgme_verify_result_t status)
70 {
71         unsigned long validity = 0;
72         gpgme_signature_t sig = NULL;
73         
74         if (GPOINTER_TO_INT(status) == -GPG_ERR_SYSTEM_ERROR) {
75                 debug_print("system error\n");
76                 return SIGNATURE_CHECK_FAILED;
77         }
78
79         if (status == NULL) {
80                 debug_print("status == NULL\n");
81                 return SIGNATURE_UNCHECKED;
82         }
83         sig = status->signatures;
84
85         if (sig == NULL) {
86                 debug_print("sig == NULL\n");
87                 return SIGNATURE_UNCHECKED;
88         }
89         validity = sig->validity;
90
91         debug_print("err code %d\n", gpg_err_code(sig->status));
92         switch (gpg_err_code(sig->status)) {
93         case GPG_ERR_NO_ERROR:
94                 switch (gpg_err_code(sig->validity)) {
95                 case GPGME_VALIDITY_NEVER:
96                         return SIGNATURE_INVALID;
97                 case GPGME_VALIDITY_UNKNOWN:
98                 case GPGME_VALIDITY_UNDEFINED:
99                 case GPGME_VALIDITY_MARGINAL:
100                 case GPGME_VALIDITY_FULL:
101                 case GPGME_VALIDITY_ULTIMATE:
102                         return SIGNATURE_OK;
103                 default:
104                         return SIGNATURE_CHECK_FAILED;
105                 }
106         case GPG_ERR_SIG_EXPIRED:
107         case GPG_ERR_KEY_EXPIRED:
108                 return SIGNATURE_WARN;
109         case GPG_ERR_BAD_SIGNATURE:
110                 return SIGNATURE_INVALID;
111         case GPG_ERR_NO_PUBKEY:
112                 return SIGNATURE_CHECK_FAILED;
113         default:
114                 return SIGNATURE_CHECK_FAILED;
115         }
116         return SIGNATURE_CHECK_FAILED;
117 }
118
119 static const gchar *get_validity_str(unsigned long validity)
120 {
121         switch (gpg_err_code(validity)) {
122         case GPGME_VALIDITY_UNKNOWN:
123                 return _("Unknown");
124         case GPGME_VALIDITY_UNDEFINED:
125                 return _("Undefined");
126         case GPGME_VALIDITY_NEVER:
127                 return _("Never");
128         case GPGME_VALIDITY_MARGINAL:
129                 return _("Marginal");
130         case GPGME_VALIDITY_FULL:
131                 return _("Full");
132         case GPGME_VALIDITY_ULTIMATE:
133                 return _("Ultimate");
134         default:
135                 return _("Error");
136         }
137 }
138
139 static gchar *extract_name(const char *uid)
140 {
141         if (uid == NULL)
142                 return NULL;
143         if (!strncmp(uid, "CN=", 3)) {
144                 gchar *result = g_strdup(uid+3);
145                 if (strstr(result, ","))
146                         *(strstr(result, ",")) = '\0';
147                 return result;
148         } else if (strstr(uid, ",CN=")) {
149                 gchar *result = g_strdup(strstr(uid, ",CN=")+4);
150                 if (strstr(result, ","))
151                         *(strstr(result, ",")) = '\0';
152                 return result;
153         } else {
154                 return g_strdup(uid);
155         }
156 }
157 gchar *sgpgme_sigstat_info_short(gpgme_ctx_t ctx, gpgme_verify_result_t status)
158 {
159         gpgme_signature_t sig = NULL;
160         gchar *uname = NULL;
161         gpgme_key_t key;
162         gchar *result = NULL;
163         gpgme_error_t err = 0;
164         static gboolean warned = FALSE;
165
166         if (GPOINTER_TO_INT(status) == -GPG_ERR_SYSTEM_ERROR) {
167                 return g_strdup_printf(_("The signature can't be checked - %s"), privacy_get_error());
168         }
169
170         if (status == NULL) {
171                 return g_strdup(_("The signature has not been checked."));
172         }
173         sig = status->signatures;
174         if (sig == NULL) {
175                 return g_strdup(_("The signature has not been checked."));
176         }
177
178         err = gpgme_get_key(ctx, sig->fpr, &key, 0);
179         if (gpg_err_code(err) == GPG_ERR_NO_AGENT) {
180                 if (!warned)
181                         alertpanel_error(_("PGP Core: Can't get key - no gpg-agent running."));
182                 else
183                         g_warning(_("PGP Core: Can't get key - no gpg-agent running."));
184                 warned = TRUE;
185         }
186         if (key)
187                 uname = extract_name(key->uids->uid);
188         else
189                 uname = g_strdup("<?>");
190         switch (gpg_err_code(sig->status)) {
191         case GPG_ERR_NO_ERROR:
192                 switch (gpg_err_code(sig->validity)) {
193                 case GPGME_VALIDITY_MARGINAL:
194                 case GPGME_VALIDITY_FULL:
195                 case GPGME_VALIDITY_ULTIMATE:
196                         result = g_strdup_printf(_("Good signature from %s."), uname);
197                         break;
198                 case GPGME_VALIDITY_UNKNOWN:
199                 case GPGME_VALIDITY_UNDEFINED:
200                 case GPGME_VALIDITY_NEVER:
201                 default:
202                         result = g_strdup_printf(_("Good signature (untrusted) from %s."), uname);
203                         break;
204                 }
205                 break;
206         case GPG_ERR_SIG_EXPIRED:
207                 result = g_strdup_printf(_("Expired signature from %s."), uname);
208                 break;
209         case GPG_ERR_KEY_EXPIRED:
210                 result = g_strdup_printf(_("Expired key from %s."), uname);
211                 break;
212         case GPG_ERR_BAD_SIGNATURE:
213                 result = g_strdup_printf(_("Bad signature from %s."), uname);
214                 break;
215         case GPG_ERR_NO_PUBKEY: {
216                 gchar *id = g_strdup(sig->fpr + strlen(sig->fpr)-8);
217                 result = g_strdup_printf(_("Key 0x%s not available to verify this signature."), id);
218                 g_free(id);
219                 break;
220                 }
221         default:
222                 result = g_strdup(_("The signature has not been checked."));
223                 break;
224         }
225         if (result == NULL)
226                 result = g_strdup(_("Error"));
227         g_free(uname);
228         return result;
229 }
230
231 gchar *sgpgme_sigstat_info_full(gpgme_ctx_t ctx, gpgme_verify_result_t status)
232 {
233         gint i = 0;
234         gchar *ret;
235         GString *siginfo;
236         gpgme_signature_t sig = status->signatures;
237         
238         siginfo = g_string_sized_new(64);
239         while (sig) {
240                 gpgme_user_id_t user = NULL;
241                 gpgme_key_t key;
242
243                 const gchar *keytype, *keyid, *uid;
244                 
245                 gpgme_get_key(ctx, sig->fpr, &key, 0);
246
247                 if (key) {
248                         user = key->uids;
249                         keytype = gpgme_pubkey_algo_name(
250                                         key->subkeys->pubkey_algo);
251                         keyid = key->subkeys->keyid;
252                         uid = user->uid;
253                 } else {
254                         keytype = "?";
255                         keyid = "?";
256                         uid = "?";
257                 }
258                 g_string_append_printf(siginfo,
259                         _("Signature made using %s key ID %s\n"),
260                         keytype, keyid);
261                 
262                 switch (gpg_err_code(sig->status)) {
263                 case GPG_ERR_NO_ERROR:
264                 case GPG_ERR_KEY_EXPIRED:
265                         g_string_append_printf(siginfo,
266                                 _("Good signature from \"%s\" (Trust: %s)\n"),
267                                 uid, get_validity_str(sig->validity));
268                         break;
269                 case GPG_ERR_SIG_EXPIRED:
270                         g_string_append_printf(siginfo,
271                                 _("Expired signature from \"%s\"\n"),
272                                 uid);
273                         break;
274                 case GPG_ERR_BAD_SIGNATURE:
275                         g_string_append_printf(siginfo,
276                                 _("BAD signature from \"%s\"\n"),
277                                 uid);
278                         break;
279                 default:
280                         break;
281                 }
282                 if (sig->status != GPG_ERR_BAD_SIGNATURE) {
283                         gint j = 1;
284                         user = user ? user->next : NULL;
285                         while (user != NULL) {
286                                 g_string_append_printf(siginfo,
287                                         _("                aka \"%s\"\n"),
288                                         user->uid);
289                                 j++;
290                                 user = user->next;
291                         }
292                         g_string_append_printf(siginfo,
293                                 _("Primary key fingerprint: %s\n"), 
294                                 sig ? sig->fpr: "?");
295 #ifdef HAVE_GPGME_PKA_TRUST
296                         if (sig->pka_trust == 1 && sig->pka_address) {
297                                 g_string_append_printf(siginfo,
298                                    _("WARNING: Signer's address \"%s\" "
299                                       "does not match DNS entry\n"), 
300                                    sig->pka_address);
301                         }
302                         else if (sig->pka_trust == 2 && sig->pka_address) {
303                                 g_string_append_printf(siginfo,
304                                    _("Verified signer's address is \"%s\"\n"),
305                                    sig->pka_address);
306                                 /* FIXME: Compare the address to the
307                                  * From: address.  */
308                         }
309 #endif /*HAVE_GPGME_PKA_TRUST*/
310                 }
311
312                 g_string_append(siginfo, "\n");
313                 i++;
314                 sig = sig->next;
315         }
316
317         ret = siginfo->str;
318         g_string_free(siginfo, FALSE);
319         return ret;
320 }
321
322 gpgme_data_t sgpgme_data_from_mimeinfo(MimeInfo *mimeinfo)
323 {
324         gpgme_data_t data = NULL;
325         gpgme_error_t err;
326         FILE *fp = g_fopen(mimeinfo->data.filename, "rb");
327         gchar *tmp_file = NULL;
328
329         if (!fp) 
330                 return NULL;
331
332         tmp_file = get_tmp_file();
333         copy_file_part(fp, mimeinfo->offset, mimeinfo->length, tmp_file);
334         fclose(fp);
335         fp = g_fopen(tmp_file, "rb");
336         debug_print("tmp file %s\n", tmp_file);
337         if (!fp) 
338                 return NULL;
339         
340         err = gpgme_data_new_from_file(&data, tmp_file, 1);
341         g_unlink(tmp_file);
342         g_free(tmp_file);
343
344         debug_print("data %p (%d %d)\n", (void *)&data, mimeinfo->offset, mimeinfo->length);
345         if (err) {
346                 debug_print ("gpgme_data_new_from_file failed: %s\n",
347                              gpgme_strerror (err));
348                 privacy_set_error(_("Couldn't get data from message, %s"), gpgme_strerror(err));
349                 return NULL;
350         }
351         return data;
352 }
353
354 gpgme_data_t sgpgme_decrypt_verify(gpgme_data_t cipher, gpgme_verify_result_t *status, gpgme_ctx_t ctx)
355 {
356         struct passphrase_cb_info_s info;
357         gpgme_data_t plain;
358         gpgme_error_t err;
359
360         memset (&info, 0, sizeof info);
361         
362         if ((err = gpgme_data_new(&plain)) != GPG_ERR_NO_ERROR) {
363                 gpgme_release(ctx);
364                 privacy_set_error(_("Couldn't initialize data, %s"), gpgme_strerror(err));
365                 return NULL;
366         }
367         
368         if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
369                 if (!getenv("GPG_AGENT_INFO")) {
370                         info.c = ctx;
371                         gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
372                 }
373         } else {
374                 info.c = ctx;
375                 gpgme_set_passphrase_cb (ctx, NULL, &info);
376         }
377         
378         
379         if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
380                 err = gpgme_op_decrypt_verify(ctx, cipher, plain);
381                 if (err != GPG_ERR_NO_ERROR) {
382                         debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
383                         privacy_set_error("%s", gpgme_strerror(err));
384                         gpgmegtk_free_passphrase();
385                         gpgme_data_release(plain);
386                         return NULL;
387                 }
388
389                 err = gpgme_data_rewind(plain);
390                 if (err) {
391                         debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
392                 }
393
394                 debug_print("decrypted.\n");
395                 *status = gpgme_op_verify_result (ctx);
396         } else {
397                 err = gpgme_op_decrypt(ctx, cipher, plain);
398                 if (err != GPG_ERR_NO_ERROR) {
399                         debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
400                         gpgmegtk_free_passphrase();
401                         gpgme_data_release(plain);
402                         return NULL;
403                 }
404
405                 err = gpgme_data_rewind(plain);
406                 if (err) {
407                         debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
408                 }
409
410                 debug_print("decrypted.\n");
411                 *status = gpgme_op_verify_result (ctx);
412         }
413         return plain;
414 }
415
416 gchar *sgpgme_get_encrypt_data(GSList *recp_names, gpgme_protocol_t proto)
417 {
418         SelectionResult result = KEY_SELECTION_CANCEL;
419         gpgme_key_t *keys = gpgmegtk_recipient_selection(recp_names, &result,
420                                 proto);
421         gchar *ret = NULL;
422         int i = 0;
423
424         if (!keys) {
425                 if (result == KEY_SELECTION_DONT)
426                         return g_strdup("_DONT_ENCRYPT_");
427                 else
428                         return NULL;
429         }
430         while (keys[i]) {
431                 gpgme_subkey_t skey = keys[i]->subkeys;
432                 gchar *fpr = skey->fpr;
433                 gchar *tmp = NULL;
434                 debug_print("adding %s\n", fpr);
435                 tmp = g_strconcat(ret?ret:"", fpr, " ", NULL);
436                 g_free(ret);
437                 ret = tmp;
438                 i++;
439         }
440         return ret;
441 }
442
443 gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account)
444 {
445         GPGAccountConfig *config;
446
447         gpgme_signers_clear(ctx);
448
449         config = prefs_gpg_account_get_config(account);
450
451         switch(config->sign_key) {
452         case SIGN_KEY_DEFAULT:
453                 debug_print("using default gnupg key\n");
454                 break;
455         case SIGN_KEY_BY_FROM:
456                 debug_print("using key for %s\n", account->address);
457                 break;
458         case SIGN_KEY_CUSTOM:
459                 debug_print("using key for %s\n", config->sign_key_id);
460                 break;
461         }
462
463         if (config->sign_key != SIGN_KEY_DEFAULT) {
464                 gchar *keyid;
465                 gpgme_key_t key;
466                 gpgme_error_t err;
467
468                 if (config->sign_key == SIGN_KEY_BY_FROM)
469                         keyid = account->address;
470                 else if (config->sign_key == SIGN_KEY_CUSTOM)
471                         keyid = config->sign_key_id;
472                 else
473                         return FALSE;
474
475                 err = gpgme_op_keylist_start(ctx, keyid, 1);
476                 if (err) {
477                         g_warning("setup_signers start: %s",
478                                 gpg_strerror(err));
479                         return FALSE;
480                 }
481                 while (!(err = gpgme_op_keylist_next(ctx, &key))) {
482                         gpgme_signers_add(ctx, key);
483                         gpgme_key_release(key);
484                 }
485                 if (err && gpg_err_code(err) != GPG_ERR_EOF) {
486                         g_warning("setup_signers next: %s",
487                                 gpg_strerror(err));
488                         return FALSE;
489                 }
490                 err = gpgme_op_keylist_end(ctx);
491                 if (err) {
492                         g_warning("setup_signers end: %s",
493                                 gpg_strerror(err));
494                         return FALSE;
495                 }
496         }
497
498         prefs_gpg_account_free_config(config);
499
500         return TRUE;
501 }
502
503 void sgpgme_init()
504 {
505         gpgme_engine_info_t engineInfo;
506         if (gpgme_check_version("1.0.0")) {
507 #ifdef LC_CTYPE
508                 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
509 #endif
510 #ifdef LC_MESSAGES
511                 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
512 #endif
513                 if (!gpgme_get_engine_info(&engineInfo)) {
514                         while (engineInfo) {
515                                 debug_print("GpgME Protocol: %s\n      Version: %s\n",
516                                         gpgme_get_protocol_name(engineInfo->protocol),
517                                         engineInfo->version);
518                                 engineInfo = engineInfo->next;
519                         }
520                 }
521         } else {
522                 sgpgme_disable_all();
523
524                 if (prefs_gpg_get_config()->gpg_warning) {
525                         AlertValue val;
526
527                         val = alertpanel_full
528                                 (_("Warning"),
529                                  _("GnuPG is not installed properly, or needs "
530                                  "to be upgraded.\n"
531                                  "OpenPGP support disabled."),
532                                  GTK_STOCK_CLOSE, NULL, NULL, TRUE, NULL,
533                                  ALERT_WARNING, G_ALERTDEFAULT);
534                         if (val & G_ALERTDISABLE)
535                                 prefs_gpg_get_config()->gpg_warning = FALSE;
536                 }
537         }
538 }
539
540 void sgpgme_done()
541 {
542         gpgmegtk_free_passphrase();
543 }
544
545 #endif /* USE_GPGME */