Statistics
| Revision:

root / src / rfc2015.c @ 1891

History | View | Annotate | Download (41.7 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 2001 Werner Koch (dd9jn)
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 */
19
20
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#if USE_GPGME
25
26
#include "defs.h"
27
28
#include <glib.h>
29
#include <glib/gi18n.h>
30
#include <stdio.h>
31
#include <string.h>
32
#include <locale.h>
33
#include <ctype.h>
34
#include <errno.h>
35
36
#include <gpgme.h>
37
38
#include "procmsg.h"
39
#include "procmime.h"
40
#include "procheader.h"
41
#include "base64.h"
42
#include "uuencode.h"
43
#include "unmime.h"
44
#include "codeconv.h"
45
#include "utils.h"
46
#include "prefs_common.h"
47
#include "passphrase.h"
48
#include "select-keys.h"
49
#include "sigstatus.h"
50
#include "rfc2015.h"
51
52
#define DIM(v)     (sizeof(v) / sizeof((v)[0]))
53
54
static gboolean gpg_available = TRUE;
55
56
static gchar *content_names[] = {
57
        "Content-Type",
58
        "Content-Disposition",
59
        "Content-Transfer-Encoding",
60
        NULL
61
};
62
63
static gchar *mime_version_name[] = {
64
        "Mime-Version",
65
        NULL
66
};
67
68
#if 0
69
static void dump_mimeinfo(const gchar *text, MimeInfo *x)
70
{
71
        debug_print("MimeInfo[%s] %p  level=%d\n", text, x, x ? x->level : 0);
72
        if (!x)
73
                return;
74
75
        debug_print("      enc=`%s' enc_type=%d mime_type=%d\n",
76
                    x->encoding, x->encoding_type, x->mime_type);
77
        debug_print("      cont_type=`%s' cs=`%s' name=`%s' bnd=`%s'\n",
78
                    x->content_type, x->charset, x->name, x->boundary );
79
        debug_print("      cont_disp=`%s' fname=`%s' fpos=%ld size=%u, lvl=%d\n",
80
                    x->content_disposition, x->filename, x->fpos, x->size,
81
                    x->level );
82
        dump_mimeinfo(".main", x->main );
83
        dump_mimeinfo(".sub", x->sub );
84
        dump_mimeinfo(".next", x->next );
85
        debug_print("MimeInfo[.parent] %p\n", x );
86
        dump_mimeinfo(".children", x->children );
87
        dump_mimeinfo(".plaintext", x->plaintext );
88
}
89
90
static void dump_part(MimeInfo *mimeinfo, FILE *fp)
91
{
92
        guint size = mimeinfo->size;
93
        gint c;
94
95
        if (fseek(fp, mimeinfo->fpos, SEEK_SET)) {
96
                debug_print("dump_part: fseek error\n");
97
                return;
98
        }
99
100
        debug_print("--- begin dump_part ----\n");
101
        while (size-- && (c = getc (fp)) != EOF)
102
                putc(c, stderr);
103
        if (ferror(fp))
104
                debug_print("dump_part: read error\n");
105
        debug_print("--- end dump_part ----\n");
106
}
107
#endif
108
109
void rfc2015_disable_all(void)
110
{
111
        gpg_available = FALSE;
112
}
113
114
gboolean rfc2015_is_available(void)
115
{
116
        return gpg_available;
117
}
118
119
void rfc2015_secure_remove(const gchar *fname)
120
{
121
        if (!fname)
122
                return;
123
        /* fixme: overwrite the file first */
124
        g_remove(fname);
125
}
126
127
static void sig_status_for_key(GString *str, gpgme_ctx_t ctx,
128
                               gpgme_signature_t sig)
129
{
130
        gpgme_key_t key;
131
        gpgme_user_id_t user;
132
        gpgme_error_t err;
133
134
        err = gpgme_get_key(ctx, sig->fpr, &key, 0);
135
        if (err || key == NULL || key->uids->uid == NULL) {
136
                if (err)
137
                        debug_print("gpgme_get_key failed: %s\n",
138
                                    gpgme_strerror(err));
139
                g_string_sprintfa(str, "%s\n",
140
                                  gpgmegtk_sig_status_to_string (sig, FALSE));
141
                if ((sig->fpr != NULL) && (*(sig->fpr) != '\0'))
142
                        g_string_sprintfa
143
                                (str, "Key fingerprint: %s\n", sig->fpr);
144
                g_string_append(str, _("Cannot find user ID for this key."));
145
                g_string_append(str, "\n");
146
                return;
147
        }
148
        user = key->uids;
149
        g_string_sprintfa
150
                (str, gpgmegtk_sig_status_to_string (sig, TRUE), user->uid);
151
        g_string_append(str, "\n");
152
153
        user = user->next;
154
        while (user) {
155
                g_string_sprintfa
156
                        (str, _("                aka \"%s\"\n"), user->uid);
157
                user = user->next;
158
        }
159
}
160
161
static gchar *sig_status_full(gpgme_ctx_t ctx, gpgme_verify_result_t result)
162
{
163
        GString *str;
164
        gpgme_signature_t sig;
165
        time_t created;
166
        struct tm *ctime_val;
167
        gchar ctime_str[80];
168
        gchar *ctime_str_utf8;
169
        gchar *retval;
170
171
        g_return_val_if_fail(result != NULL, NULL);
172
173
        str = g_string_new("");
174
175
        sig = result->signatures;
176
        while (sig != NULL) {
177
                if (sig->timestamp != 0) {
178
                        created = sig->timestamp;
179
                        ctime_val = localtime(&created);
180
                        my_strftime(ctime_str, sizeof (ctime_str), "%c",
181
                                    ctime_val);
182
                        ctime_str_utf8 = g_locale_to_utf8(ctime_str, -1,
183
                                                          NULL, NULL, NULL);
184
                        if (!ctime_str_utf8)
185
                                ctime_str_utf8 = g_strdup(ctime_str);
186
                        g_string_sprintfa(str, _("Signature made at %s\n"),
187
                                          ctime_str_utf8);
188
                        g_free(ctime_str_utf8);
189
                }
190
                sig_status_for_key(str, ctx, sig);
191
                if (sig->next)
192
                        g_string_append(str, "\n\n");
193
                sig = sig->next;
194
        }
195
196
        retval = str->str;
197
        g_string_free(str, FALSE);
198
        return retval;
199
}
200
201
static void check_signature(MimeInfo *mimeinfo, MimeInfo *partinfo, FILE *fp)
202
{
203
        gpgme_ctx_t ctx = NULL;
204
        gpgme_error_t err;
205
        gpgme_data_t sig = NULL, text = NULL;
206
        gpgme_verify_result_t verifyresult = NULL;
207
        GpgmegtkSigStatus statuswindow = NULL;
208
        const gchar *result = NULL;
209
        gchar *tmp_file;
210
        gint n_exclude_chars = 0;
211
212
        if (prefs_common.gpg_signature_popup)
213
                statuswindow = gpgmegtk_sig_status_create();
214
215
        err = gpgme_new(&ctx);
216
        if (err) {
217
                debug_print("gpgme_new failed: %s\n", gpgme_strerror(err));
218
                goto leave;
219
        }
220
221
        if (rfc2015_is_pkcs7_signature_part(partinfo)) {
222
                debug_print("pkcs7 signature detected\n");
223
                gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
224
        }
225
226
        /* don't include the last empty line.
227
           It does not belong to the signed text */
228
        if (mimeinfo->children->size > 0) {
229
                if (fseek(fp, mimeinfo->children->fpos + mimeinfo->children->size - 1,
230
                          SEEK_SET) < 0) {
231
                        perror("fseek");
232
                        goto leave;
233
                }
234
                if (fgetc(fp) == '\n') {
235
                        n_exclude_chars++;
236
                        if (mimeinfo->children->size > 1) {
237
                                if (fseek(fp, mimeinfo->children->fpos + mimeinfo->children->size - 2,
238
                                          SEEK_SET) < 0) {
239
                                        perror("fseek");
240
                                        goto leave;
241
                                }
242
                                if (fgetc(fp) == '\r')
243
                                        n_exclude_chars++;
244
                        }
245
                }
246
        }
247
248
        /* canonicalize the file part. */
249
        tmp_file = get_tmp_file();
250
        if (copy_file_part(fp, mimeinfo->children->fpos,
251
                           mimeinfo->children->size - n_exclude_chars,
252
                           tmp_file) < 0) {
253
                g_free(tmp_file);
254
                goto leave;
255
        }
256
        if (canonicalize_file_replace(tmp_file) < 0) {
257
                g_unlink(tmp_file);
258
                g_free(tmp_file);
259
                goto leave;
260
        }
261
262
        err = gpgme_data_new_from_file(&text, tmp_file, 1);
263
264
        g_unlink(tmp_file);
265
        g_free(tmp_file);
266
267
        if (!err)
268
                err = gpgme_data_new_from_filepart(&sig, NULL, fp,
269
                                                   partinfo->fpos,
270
                                                   partinfo->size);
271
        if (err) {
272
                debug_print("gpgme_data_new_from_filepart failed: %s\n",
273
                            gpgme_strerror (err));
274
                goto leave;
275
        }
276
277
#if 0
278
        if (partinfo->encoding_type == ENC_BASE64) {
279
                err = gpgme_data_set_encoding(sig, GPGME_DATA_ENCODING_BASE64);
280
                if (err) {
281
                        debug_print("gpgme_data_set_encoding failed: %s\n",
282
                                    gpgme_strerror (err));
283
                        goto leave;
284
                }
285
        }
286
#endif
287
288
        err = gpgme_op_verify(ctx, sig, text, NULL);
289
        if (err)  {
290
                debug_print("gpgme_op_verify failed: %s\n",
291
                            gpgme_strerror (err));
292
                goto leave;
293
        }
294
        verifyresult = gpgme_op_verify_result(ctx);
295
296
        /* FIXME: check what the heck this sig_status_full stuff is.
297
         * Maybe it belongs in sigstatus.c 
298
         *
299
         * I think it belongs here as it is interfacing with gmime (Toshio). */
300
        g_free (partinfo->sigstatus_full);
301
        partinfo->sigstatus_full = sig_status_full(ctx, verifyresult);
302
303
leave:
304
        if (verifyresult) {
305
                result = gpgmegtk_sig_status_to_string
306
                        (verifyresult->signatures, FALSE);
307
        } else {
308
                result = _("Error verifying the signature");
309
        }
310
        debug_print("verification status: %s\n", result);
311
        if (prefs_common.gpg_signature_popup)
312
                gpgmegtk_sig_status_update(statuswindow, ctx);
313
314
        g_free (partinfo->sigstatus);
315
        partinfo->sigstatus = g_strdup (result);
316
317
        gpgme_data_release(sig);
318
        gpgme_data_release(text);
319
        gpgme_release(ctx);
320
        if (prefs_common.gpg_signature_popup)
321
                gpgmegtk_sig_status_destroy(statuswindow);
322
}
323
324
/*
325
 * Copy a gpgme data object to a temporary file and
326
 * return this filename 
327
 */
328
#if 0
329
static gchar *copy_gpgmedata_to_temp(GpgmeData data, guint *length)
330
{
331
        static gint id;
332
        gchar *tmp;
333
        FILE *fp;
334
        gchar buf[100];
335
        size_t nread;
336
        GpgmeError err;
337
338
        tmp = g_strdup_printf("%s%cgpgtmp.%08x",
339
                              get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);
340
341
        if ((fp = g_fopen(tmp, "wb")) == NULL) {
342
                FILE_OP_ERROR(tmp, "fopen");
343
                g_free(tmp);
344
                return NULL;
345
        }
346
347
        err = gpgme_data_rewind(data);
348
        if (err)
349
                debug_print("gpgme_data_rewind failed: %s\n",
350
                            gpgme_strerror(err));
351
352
        while (!(err = gpgme_data_read(data, buf, 100, &nread))) {
353
                fwrite(buf, nread, 1, fp);
354
        }
355
356
        if (err != GPGME_EOF)
357
                debug_print("gpgme_data_read failed: %s\n",
358
                            gpgme_strerror(err));
359
360
        fclose (fp);
361
        *length = nread;
362
363
        return tmp;
364
}
365
#endif
366
367
static gpgme_data_t pgp_decrypt(MsgInfo *msginfo, MimeInfo *partinfo, FILE *fp)
368
{
369
        gpgme_ctx_t ctx = NULL;
370
        gpgme_error_t err;
371
        gpgme_data_t cipher = NULL, plain = NULL;
372
        struct passphrase_cb_info_s info;
373
        gpgme_verify_result_t verifyresult = NULL;
374
        const gchar *result = NULL;
375
376
        memset(&info, 0, sizeof info);
377
378
        err = gpgme_new(&ctx);
379
        if (err) {
380
                debug_print("gpgme_new failed: %s\n", gpgme_strerror(err));
381
                goto leave;
382
        }
383
384
        err = gpgme_data_new_from_filepart(&cipher, NULL, fp,
385
                                           partinfo->fpos, partinfo->size);
386
        if (err) {
387
                debug_print("gpgme_data_new_from_filepart failed: %s\n",
388
                            gpgme_strerror(err));
389
                goto leave;
390
        }
391
392
        err = gpgme_data_new(&plain);
393
        if (err) {
394
                debug_print("gpgme_new failed: %s\n", gpgme_strerror(err));
395
                goto leave;
396
        }
397
398
        if (!g_getenv("GPG_AGENT_INFO")) {
399
                info.c = ctx;
400
                gpgme_set_passphrase_cb(ctx, gpgmegtk_passphrase_cb, &info);
401
        }
402
403
        err = gpgme_op_decrypt_verify(ctx, cipher, plain);
404
405
        msginfo->encinfo = g_new0(MsgEncryptInfo, 1);
406
407
        if (err) {
408
                gpgmegtk_free_passphrase();
409
                debug_print("decryption failed: %s\n", gpgme_strerror(err));
410
                gpgme_data_release(plain);
411
                plain = NULL;
412
                msginfo->encinfo->decryption_failed = TRUE;
413
                goto leave;
414
        }
415
416
        debug_print("** decryption succeeded\n");
417
418
        verifyresult = gpgme_op_verify_result(ctx);
419
        if (verifyresult && verifyresult->signatures) {
420
                result = gpgmegtk_sig_status_to_string(verifyresult->signatures,
421
                                                       FALSE);
422
                msginfo->encinfo->sigstatus = g_strdup(result);
423
                msginfo->encinfo->sigstatus_full =
424
                        sig_status_full(ctx, verifyresult);
425
                debug_print("verification status: %s\n", result);
426
                debug_print("full status: %s\n",
427
                            msginfo->encinfo->sigstatus_full);
428
                if (prefs_common.gpg_signature_popup) {
429
                        GpgmegtkSigStatus statuswindow;
430
                        statuswindow = gpgmegtk_sig_status_create();
431
                        gpgmegtk_sig_status_update(statuswindow, ctx);
432
                        gpgmegtk_sig_status_destroy(statuswindow);
433
                }
434
        }
435
436
437
leave:
438
        gpgme_data_release(cipher);
439
        gpgme_release(ctx);
440
        return plain;
441
}
442
443
MimeInfo **rfc2015_find_signature(MimeInfo *mimeinfo)
444
{
445
        MimeInfo *partinfo;
446
        MimeInfo **signedinfo = NULL;
447
        gint n = 0;
448
449
        if (!mimeinfo)
450
                return NULL;
451
452
        /* We could have a signature nested within multipart/mixed so
453
         * recurse to find it.
454
         */
455
        if (!g_ascii_strcasecmp(mimeinfo->content_type, "multipart/mixed")) {
456
                for (partinfo = mimeinfo->children; partinfo != NULL;
457
                        partinfo = partinfo->next) {
458
                        signedinfo = rfc2015_find_signature(partinfo);
459
                        if (signedinfo) {
460
                                return signedinfo;
461
                        }
462
                }
463
                return NULL;
464
        }
465
        if (g_ascii_strcasecmp(mimeinfo->content_type, "multipart/signed"))
466
                return NULL;
467
468
        debug_print("** multipart/signed encountered\n");
469
470
        /* check that we have at least 2 parts of the correct type */
471
        for (partinfo = mimeinfo->children;
472
                partinfo != NULL; partinfo = partinfo->next) {
473
                if (++n > 1  && rfc2015_is_signature_part(partinfo))
474
                        break;
475
        }
476
477
        if (partinfo) {
478
                signedinfo = g_malloc(sizeof(MimeInfo *) * 2);
479
                signedinfo[0] = mimeinfo;
480
                signedinfo[1] = partinfo;
481
        }
482
        /* This is NULL if partinfo was not set */
483
        return signedinfo;
484
}
485
486
gboolean rfc2015_has_signature(MimeInfo *mimeinfo)
487
{
488
        return rfc2015_find_signature(mimeinfo) != NULL;
489
}
490
491
void rfc2015_check_signature(MimeInfo *mimeinfo, FILE *fp)
492
{
493
        MimeInfo **signedinfo;
494
495
        signedinfo = rfc2015_find_signature(mimeinfo);
496
        if (!signedinfo)
497
                return;
498
499
#if 0
500
        g_message("** yep, it is a pgp signature");
501
        dump_mimeinfo("gpg-signature", partinfo );
502
        dump_part(partinfo, fp );
503
        dump_mimeinfo("signed text", mimeinfo->children );
504
        dump_part(mimeinfo->children, fp);
505
#endif
506
507
        check_signature(signedinfo[0], signedinfo[1], fp);
508
        g_free(signedinfo);
509
}
510
511
gboolean rfc2015_is_pgp_signature_part(MimeInfo *mimeinfo)
512
{
513
        if (!mimeinfo || !mimeinfo->content_type)
514
                return FALSE;
515
516
        return !g_ascii_strcasecmp(mimeinfo->content_type,
517
                                   "application/pgp-signature");
518
}
519
520
gboolean rfc2015_is_pkcs7_signature_part(MimeInfo *mimeinfo)
521
{
522
        const gchar *c_type;
523
524
        if (!mimeinfo || !mimeinfo->content_type)
525
                return FALSE;
526
527
        c_type = mimeinfo->content_type;
528
529
        return (!g_ascii_strcasecmp(c_type, "application/pkcs7-signature") ||
530
                !g_ascii_strcasecmp(c_type, "application/x-pkcs7-signature"));
531
}
532
533
gboolean rfc2015_is_signature_part(MimeInfo *mimeinfo)
534
{
535
        return (rfc2015_is_pgp_signature_part(mimeinfo) ||
536
                rfc2015_is_pkcs7_signature_part(mimeinfo));
537
}
538
539
gint rfc2015_is_encrypted(MimeInfo *mimeinfo)
540
{
541
        if (!mimeinfo || mimeinfo->mime_type != MIME_MULTIPART)
542
                return 0;
543
        if (g_ascii_strcasecmp(mimeinfo->content_type, "multipart/encrypted"))
544
                return 0;
545
        /* fixme: we should check the protocol parameter */
546
        return 1;
547
}
548
549
gboolean rfc2015_msg_is_encrypted(const gchar *file)
550
{
551
        FILE *fp;
552
        MimeInfo *mimeinfo;
553
        gint ret;
554
555
        if ((fp = g_fopen(file, "rb")) == NULL)
556
                return FALSE;
557
558
        mimeinfo = procmime_scan_mime_header(fp);
559
        if(!mimeinfo) {
560
                fclose(fp);
561
                return FALSE;
562
        }
563
564
        ret = rfc2015_is_encrypted(mimeinfo);
565
        procmime_mimeinfo_free_all(mimeinfo);
566
        return ret != 0 ? TRUE : FALSE;
567
}
568
569
static gint name_cmp(const gchar *a, const gchar *b)
570
{
571
        for( ; *a && *b; a++, b++) {
572
                if (*a != *b &&
573
                    g_ascii_toupper(*(guchar *)a) != g_ascii_toupper(*(guchar *)b))
574
                        return 1;
575
        }
576
577
        return *a != *b;
578
}
579
580
static gint headerp(gchar *p, gchar **names)
581
{
582
        gint i, c;
583
        gchar *p2;
584
585
        p2 = strchr(p, ':');
586
        if (!p2 || p == p2) {
587
                return 0;
588
        }
589
        if (p2[-1] == ' ' || p2[-1] == '\t') {
590
                return 0;
591
        }
592
593
        if (!names[0])
594
                return 1;
595
596
        c = *p2;
597
        *p2 = 0;
598
        for(i = 0 ; names[i] != NULL; i++) {
599
                if (!name_cmp(names[i], p))
600
                        break;
601
        }
602
        *p2 = c;
603
604
        return names[i] != NULL;
605
}
606
607
608
#define DECRYPTION_ABORT() \
609
{ \
610
        procmime_mimeinfo_free_all(tmpinfo); \
611
        if (msginfo->encinfo) \
612
                msginfo->encinfo->decryption_failed = TRUE; \
613
        return; \
614
}
615
616
void rfc2015_decrypt_message(MsgInfo *msginfo, MimeInfo *mimeinfo, FILE *fp)
617
{
618
        static gint id;
619
        MimeInfo *tmpinfo, *partinfo;
620
        gint ver_ok = 0;
621
        gchar *fname;
622
        gpgme_data_t plain;
623
        FILE *dstfp;
624
        ssize_t nread;
625
        gchar buf[BUFFSIZE];
626
        gint in_cline;
627
        gpgme_error_t err;
628
629
        g_return_if_fail(msginfo != NULL);
630
        g_return_if_fail(mimeinfo != NULL);
631
        g_return_if_fail(fp != NULL);
632
        g_return_if_fail(mimeinfo->mime_type == MIME_MULTIPART);
633
634
        debug_print("** decrypting multipart/encrypted message\n");
635
636
        /* skip headers */
637
        if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
638
                perror("fseek");
639
        tmpinfo = procmime_scan_mime_header(fp);
640
        if (!tmpinfo || tmpinfo->mime_type != MIME_MULTIPART) {
641
                DECRYPTION_ABORT();
642
        }
643
644
        procmime_scan_multipart_message(tmpinfo, fp);
645
646
        /* check that we have the 2 parts */
647
        partinfo = tmpinfo->children;
648
        if (!partinfo || !partinfo->next) {
649
                DECRYPTION_ABORT();
650
        }
651
        if (!g_ascii_strcasecmp(partinfo->content_type,
652
                                "application/pgp-encrypted")) {
653
                /* Fixme: check that the version is 1 */
654
                ver_ok = 1;
655
        }
656
        partinfo = partinfo->next;
657
        if (ver_ok &&
658
            !g_ascii_strcasecmp(partinfo->content_type,
659
                                "application/octet-stream")) {
660
                if (partinfo->next)
661
                        g_warning("oops: pgp_encrypted with more than 2 parts");
662
        } else {
663
                DECRYPTION_ABORT();
664
        }
665
666
        debug_print("** yep, it is pgp encrypted\n");
667
668
        plain = pgp_decrypt(msginfo, partinfo, fp);
669
        if (!plain) {
670
                DECRYPTION_ABORT();
671
        }
672
673
        fname = g_strdup_printf("%s%cplaintext.%08x",
674
                                get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id);
675
676
        if ((dstfp = g_fopen(fname, "wb")) == NULL) {
677
                FILE_OP_ERROR(fname, "fopen");
678
                g_free(fname);
679
                DECRYPTION_ABORT();
680
        }
681
682
        /* write the orginal header to the new file */
683
        if (fseek(fp, tmpinfo->fpos, SEEK_SET) < 0)
684
                perror("fseek");
685
686
        in_cline = 0;
687
        while (fgets(buf, sizeof(buf), fp)) {
688
                if (headerp(buf, content_names)) {
689
                        in_cline = 1;
690
                        continue;
691
                }
692
                if (in_cline) {
693
                        if (buf[0] == ' ' || buf[0] == '\t')
694
                                continue;
695
                        in_cline = 0;
696
                }
697
                if (buf[0] == '\r' || buf[0] == '\n')
698
                        break;
699
                fputs(buf, dstfp);
700
        }
701
702
        err = (gpgme_data_seek(plain, 0, SEEK_SET) == -1) ?
703
                gpgme_error_from_errno(errno) : 0;
704
        if (err)
705
                debug_print("gpgme_data_seek failed: %s\n", gpgme_strerror(err));
706
707
        nread = gpgme_data_read(plain, buf, sizeof(buf));
708
        while (nread > 0) {
709
                fwrite (buf, nread, 1, dstfp);
710
                nread = gpgme_data_read(plain, buf, sizeof(buf));
711
        }
712
713
        if (nread != 0) {
714
                debug_print("gpgme_data_read failed: %s\n",
715
                            gpgme_strerror(gpgme_error_from_errno(errno)));
716
        }
717
718
        fclose(dstfp);
719
        procmime_mimeinfo_free_all(tmpinfo);
720
721
        msginfo->encinfo->plaintext_file = fname;
722
}
723
724
#undef DECRYPTION_ABORT
725
726
FILE *rfc2015_open_message_decrypted(MsgInfo *msginfo, MimeInfo **mimeinfo)
727
{
728
        FILE *fp;
729
        MimeInfo *mimeinfo_;
730
        glong fpos;
731
732
        g_return_val_if_fail(msginfo != NULL, NULL);
733
734
        if (mimeinfo) *mimeinfo = NULL;
735
736
        if ((fp = procmsg_open_message(msginfo)) == NULL) return NULL;
737
738
        mimeinfo_ = procmime_scan_mime_header(fp);
739
        if (!mimeinfo_) {
740
                fclose(fp);
741
                return NULL;
742
        }
743
744
        if (!MSG_IS_ENCRYPTED(msginfo->flags) &&
745
            rfc2015_is_encrypted(mimeinfo_)) {
746
                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_ENCRYPTED);
747
        }
748
749
        if (MSG_IS_ENCRYPTED(msginfo->flags) &&
750
            (!msginfo->encinfo ||
751
             (!msginfo->encinfo->plaintext_file &&
752
              !msginfo->encinfo->decryption_failed))) {
753
                fpos = ftell(fp);
754
                rfc2015_decrypt_message(msginfo, mimeinfo_, fp);
755
                if (msginfo->encinfo &&
756
                    msginfo->encinfo->plaintext_file &&
757
                    !msginfo->encinfo->decryption_failed) {
758
                        fclose(fp);
759
                        procmime_mimeinfo_free_all(mimeinfo_);
760
761
                        if ((fp = procmsg_open_message(msginfo)) == NULL)
762
                                return NULL;
763
                        mimeinfo_ = procmime_scan_mime_header(fp);
764
                        if (!mimeinfo_) {
765
                                fclose(fp);
766
                                return NULL;
767
                        }
768
                } else {
769
                        if (fseek(fp, fpos, SEEK_SET) < 0)
770
                                perror("fseek");
771
                }
772
        }
773
774
        if (mimeinfo) *mimeinfo = mimeinfo_;
775
        return fp;
776
}
777
778
779
/*
780
 * plain contains an entire mime object.
781
 * Encrypt it and return an GpgmeData object with the encrypted version of
782
 * the file or NULL in case of error.
783
 */
784
static gpgme_data_t pgp_encrypt(gpgme_data_t plain, gpgme_key_t kset[])
785
{
786
        gpgme_ctx_t ctx = NULL;
787
        gpgme_error_t err;
788
        gpgme_data_t cipher = NULL;
789
790
        err = gpgme_new(&ctx);
791
        if (!err)
792
                err = gpgme_data_new(&cipher);
793
        if (!err) {
794
                gpgme_set_armor(ctx, 1);
795
                err = (gpgme_data_seek(plain, 0, SEEK_SET) == -1) ?
796
                        gpgme_error_from_errno(errno) : 0;
797
                if (!err) {
798
                        /*
799
                         * Note -- it is currently the responsibility of select-keys.c::
800
                         * gpgmegtk_recipient_selection() to prompt the user whether to
801
                         * encrypt to recipients whose key is not trusted.
802
                         */
803
                        err = gpgme_op_encrypt(ctx, kset,
804
                                               GPGME_ENCRYPT_ALWAYS_TRUST,
805
                                               plain, cipher);
806
                }
807
        }
808
809
        if (err) {
810
                g_warning("pgp_encrypt(): encryption failed: %s\n",
811
                          gpgme_strerror(err));
812
                gpgme_data_release(cipher);
813
                cipher = NULL;
814
        } else {
815
                debug_print("** encryption succeeded\n");
816
        }
817
818
        gpgme_release(ctx);
819
        return cipher;
820
}
821
822
/*
823
 * Create and return a list of keys matching a key id
824
 */
825
826
GSList *rfc2015_create_signers_list(const gchar *keyid)
827
{
828
        GSList *key_list = NULL;
829
        gpgme_ctx_t list_ctx = NULL;
830
        GSList *p;
831
        gpgme_error_t err;
832
        gpgme_key_t key;
833
834
        err = gpgme_new(&list_ctx);
835
        if (err)
836
                goto leave;
837
        err = gpgme_op_keylist_start(list_ctx, keyid, 1);
838
        if (err)
839
                goto leave;
840
        while (!(err = gpgme_op_keylist_next(list_ctx, &key))) {
841
                key_list = g_slist_append(key_list, key);
842
        }
843
        if (gpgme_err_code(err) != GPG_ERR_EOF)
844
                goto leave;
845
        err = 0;
846
        if (key_list == NULL) {
847
                debug_print("no keys found for keyid \"%s\"\n", keyid);
848
        }
849
850
leave:
851
        if (err) {
852
                debug_print("rfc2015_create_signers_list failed: %s\n",
853
                            gpgme_strerror(err));
854
                for (p = key_list; p != NULL; p = p->next)
855
                        gpgme_key_unref((gpgme_key_t)p->data);
856
                g_slist_free(key_list);
857
        }
858
        if (list_ctx)
859
                gpgme_release(list_ctx);
860
        return err ? NULL : key_list;
861
}
862
863
/*
864
 * Encrypt the file by extracting all recipients and finding the
865
 * encryption keys for all of them.  The file content is then replaced
866
 * by the encrypted one.  */
867
gint rfc2015_encrypt(const gchar *file, GSList *recp_list)
868
{
869
        FILE *fp = NULL;
870
        gchar buf[BUFFSIZE];
871
        gint i, clineidx, saved_last;
872
        gchar *clines[3] = {NULL};
873
        gpgme_error_t err;
874
        gpgme_data_t header = NULL;
875
        gpgme_data_t plain = NULL;
876
        gpgme_data_t cipher = NULL;
877
        gpgme_key_t *kset = NULL;
878
        ssize_t bytesRW = 0;
879
        gint mime_version_seen = 0;
880
        gchar *boundary;
881
882
        boundary = generate_mime_boundary("Encrypt");
883
884
        /* Create the list of recipients */
885
        kset = gpgmegtk_recipient_selection(recp_list);
886
        if (!kset) {
887
                debug_print("error creating recipient list\n");
888
                goto failure;
889
        }
890
891
        /* Open the source file */
892
        if ((fp = g_fopen(file, "rb")) == NULL) {
893
                FILE_OP_ERROR(file, "fopen");
894
                goto failure;
895
        }
896
897
        err = gpgme_data_new(&header);
898
        if (!err)
899
                err = gpgme_data_new(&plain);
900
        if (err) {
901
                debug_print("gpgme_data_new failed: %s\n", gpgme_strerror(err));
902
                goto failure;
903
        }
904
905
        /* get the content header lines from the source */
906
        clineidx = 0;
907
        saved_last = 0;
908
        while (!err && fgets(buf, sizeof(buf), fp)) {
909
                /* fixme: check for overlong lines */
910
                if (headerp(buf, content_names)) {
911
                        if (clineidx >= DIM(clines)) {
912
                                debug_print("rfc2015_encrypt: too many content lines\n");
913
                                goto failure;
914
                        }
915
                        clines[clineidx++] = g_strdup(buf);
916
                        saved_last = 1;
917
                        continue;
918
                }
919
                if (saved_last) {
920
                        if (*buf == ' ' || *buf == '\t') {
921
                                gchar *last = clines[clineidx - 1];
922
                                clines[clineidx - 1] = g_strconcat(last, buf, NULL);
923
                                g_free(last);
924
                                continue;
925
                        }
926
                        saved_last = 0;
927
                }
928
929
                if (headerp(buf, mime_version_name))
930
                        mime_version_seen = 1;
931
932
                if (buf[0] == '\r' || buf[0] == '\n')
933
                        break;
934
                bytesRW = gpgme_data_write(header, buf, strlen(buf));
935
        }
936
        if (ferror(fp)) {
937
                FILE_OP_ERROR(file, "fgets");
938
                goto failure;
939
        }
940
941
        /* write them to the temp data and add the rest of the message */
942
        for (i = 0; (bytesRW != -1) && i < clineidx; i++) {
943
                debug_print("%% %s:%d: cline=`%s'", __FILE__ ,__LINE__, clines[i]);
944
                bytesRW = gpgme_data_write(plain, clines[i], strlen(clines[i]));
945
        }
946
        if (bytesRW != -1)
947
                bytesRW = gpgme_data_write (plain, "\r\n", 2);
948
        while ((bytesRW != -1) && fgets(buf, sizeof(buf), fp)) {
949
                bytesRW = gpgme_data_write(plain, buf, strlen(buf));
950
        }
951
        if (ferror(fp)) {
952
                FILE_OP_ERROR(file, "fgets");
953
                goto failure;
954
        }
955
        if (bytesRW == -1) {
956
                debug_print("gpgme_data_write failed: %s\n",
957
                            gpgme_strerror(gpgme_error_from_errno(errno)));
958
                goto failure;
959
        }
960
961
        cipher = pgp_encrypt(plain, kset);
962
        gpgme_data_release(plain);
963
        plain = NULL;
964
        i = 0;
965
        while (kset[i] != NULL) {
966
                gpgme_key_unref(kset[i]);
967
                i++;
968
        }
969
        g_free(kset);
970
        kset = NULL;
971
        if (!cipher)
972
                goto failure;
973
974
        /* we have the encrypted message available in cipher and now we
975
         * are going to rewrite the source file. To be sure that file has
976
         * been truncated we use an approach which should work everywhere:
977
         * close the file and then reopen it for writing. It is important
978
         * that this works, otherwise it may happen that parts of the
979
         * plaintext are still in the file (The encrypted stuff is, due to
980
         * compression, usually shorter than the plaintext). 
981
         * 
982
         * Yes, there is a race condition here, but everyone, who is so
983
         * stupid to store the temp file with the plaintext in a public
984
         * directory has to live with this anyway. */
985
        if (fclose (fp)) {
986
                FILE_OP_ERROR(file, "fclose");
987
                goto failure;
988
        }
989
        if ((fp = g_fopen(file, "wb")) == NULL) {
990
                FILE_OP_ERROR(file, "fopen");
991
                goto failure;
992
        }
993
994
        /* Write the header, append new content lines, part 1 and part 2 header */
995
        err = (gpgme_data_seek(header, 0 , SEEK_SET) == -1) ?
996
              gpgme_error_from_errno(errno) : 0;
997
        if (err) {
998
                debug_print("gpgme_data_seek failed: %s\n",
999
                            gpgme_strerror(err));
1000
                goto failure;
1001
        }
1002
        bytesRW = gpgme_data_read(header, buf, BUFFSIZE);
1003
        while (bytesRW > 0) {
1004
                fwrite (buf, bytesRW, 1, fp);
1005
                bytesRW = gpgme_data_read(header, buf, BUFFSIZE);
1006
        }
1007
1008
        if (bytesRW != 0) {
1009
                debug_print("gpgme_data_read failed: %s\n",
1010
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1011
                goto failure;
1012
        }
1013
1014
        if (ferror (fp)) {
1015
                FILE_OP_ERROR(file, "fwrite");
1016
                goto failure;
1017
        }
1018
        gpgme_data_release(header);
1019
        header = NULL;
1020
1021
        if (!mime_version_seen)
1022
                fputs("MIME-Version: 1\r\n", fp);
1023
1024
        fprintf(fp,
1025
                "Content-Type: multipart/encrypted;"
1026
                " protocol=\"application/pgp-encrypted\";\r\n"
1027
                " boundary=\"%s\"\r\n"
1028
                "\r\n"
1029
                "--%s\r\n"
1030
                "Content-Type: application/pgp-encrypted\r\n"
1031
                "\r\n"
1032
                "Version: 1\r\n"
1033
                "\r\n"
1034
                "--%s\r\n"
1035
                "Content-Type: application/octet-stream\r\n"
1036
                "\r\n",
1037
                boundary, boundary, boundary);
1038
1039
        /* append the encrypted stuff */
1040
        err = (gpgme_data_seek(cipher, 0 , SEEK_SET) == -1) ?
1041
                gpgme_error_from_errno(errno) : 0;
1042
        if (err) {
1043
                debug_print("** gpgme_data_seek on cipher failed: %s\n",
1044
                            gpgme_strerror(err));
1045
                debug_print("gpgme_data_seek failed: %s\n",
1046
                            gpgme_strerror(err));
1047
                goto failure;
1048
        }
1049
1050
        bytesRW = gpgme_data_read(cipher, buf, BUFFSIZE);
1051
        while (bytesRW > 0) {
1052
                fwrite(buf, bytesRW, 1, fp);
1053
                bytesRW = gpgme_data_read(cipher, buf, BUFFSIZE);
1054
        }
1055
1056
        if (bytesRW != 0) {
1057
                debug_print("** gpgme_data_read failed: %s\n",
1058
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1059
                goto failure;
1060
        }
1061
1062
        /* and the final boundary */
1063
        fprintf(fp,
1064
                "\r\n"
1065
                "--%s--\r\n",
1066
                boundary);
1067
        fflush(fp);
1068
        if (ferror(fp)) {
1069
                FILE_OP_ERROR(file, "fwrite");
1070
                goto failure;
1071
        }
1072
        fclose(fp);
1073
        gpgme_data_release(cipher);
1074
        return 0;
1075
1076
failure:
1077
        if (fp)
1078
                fclose (fp);
1079
        gpgme_data_release(header);
1080
        gpgme_data_release(plain);
1081
        gpgme_data_release(cipher);
1082
1083
        if (kset != NULL) {
1084
                i = 0;
1085
                while (kset[i] != NULL) {
1086
                        gpgme_key_unref(kset[i]);
1087
                        i++;
1088
                }
1089
                g_free(kset);
1090
        }
1091
        g_free(boundary);
1092
        return -1; /* error */
1093
}
1094
1095
gint rfc2015_encrypt_armored(const gchar *file, GSList *recp_list)
1096
{
1097
        FILE *fp = NULL;
1098
        gchar buf[BUFFSIZE];
1099
        gint i;
1100
        gpgme_error_t err;
1101
        gpgme_data_t plain = NULL;
1102
        gpgme_data_t cipher = NULL;
1103
        gpgme_key_t *kset = NULL;
1104
        ssize_t bytesRW = 0;
1105
1106
        kset = gpgmegtk_recipient_selection(recp_list);
1107
        if (!kset) {
1108
                debug_print("error creating recipient list\n");
1109
                goto failure;
1110
        }
1111
1112
        /* Open the source file */
1113
        if ((fp = g_fopen(file, "rb")) == NULL) {
1114
                FILE_OP_ERROR(file, "fopen");
1115
                goto failure;
1116
        }
1117
1118
        err = gpgme_data_new(&plain);
1119
        if (err) {
1120
                g_warning("gpgme_data_new failed: %s\n", gpgme_strerror(err));
1121
                goto failure;
1122
        }
1123
1124
        while (bytesRW != -1 && fgets(buf, sizeof(buf), fp)) {
1125
                bytesRW = gpgme_data_write(plain, buf, strlen(buf));
1126
        }
1127
        if (ferror(fp)) {
1128
                FILE_OP_ERROR(file, "fgets");
1129
                goto failure;
1130
        }
1131
        if (bytesRW == -1) {
1132
                debug_print("gpgme_data_write failed: %s\n",
1133
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1134
                goto failure;
1135
        }
1136
1137
        cipher = pgp_encrypt(plain, kset);
1138
        gpgme_data_release(plain);
1139
        plain = NULL;
1140
        i = 0;
1141
        while (kset[i] != NULL) {
1142
                gpgme_key_unref(kset[i]);
1143
                i++;
1144
        }
1145
        g_free(kset);
1146
        kset = NULL;
1147
        if (!cipher)
1148
                goto failure;
1149
1150
        if (fclose(fp)) {
1151
                FILE_OP_ERROR(file, "fclose");
1152
                goto failure;
1153
        }
1154
        if ((fp = g_fopen(file, "wb")) == NULL) {
1155
                FILE_OP_ERROR(file, "fopen");
1156
                goto failure;
1157
        }
1158
1159
        err = (gpgme_data_seek(cipher, 0 , SEEK_SET) == -1) ?
1160
                gpgme_error_from_errno(errno) : 0;
1161
        if (err) {
1162
                debug_print("** gpgme_data_seek on cipher failed: %s\n",
1163
                            gpgme_strerror(err));
1164
                debug_print("gpgme_data_seek failed: %s\n",
1165
                            gpgme_strerror(err));
1166
                goto failure;
1167
        }
1168
1169
        bytesRW = gpgme_data_read(cipher, buf, sizeof(buf));
1170
        while (bytesRW > 0) {
1171
                fwrite(buf, bytesRW, 1, fp);
1172
                bytesRW = gpgme_data_read(cipher, buf, sizeof(buf));
1173
        }
1174
1175
        if (bytesRW != 0) {
1176
                debug_print("** gpgme_data_read failed: %s\n",
1177
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1178
                goto failure;
1179
        }
1180
1181
        fflush(fp);
1182
        if (ferror(fp)) {
1183
                FILE_OP_ERROR(file, "fwrite");
1184
                goto failure;
1185
        }
1186
        fclose(fp);
1187
        gpgme_data_release(cipher);
1188
        return 0;
1189
1190
failure:
1191
        if (fp)
1192
                fclose(fp);
1193
        gpgme_data_release(plain);
1194
        gpgme_data_release(cipher);
1195
        if (kset != NULL) {
1196
                i = 0;
1197
                while (kset[i] != NULL) {
1198
                        gpgme_key_unref(kset[i]);
1199
                        i++;
1200
                }
1201
                g_free(kset);
1202
        }
1203
1204
        return -1;
1205
}
1206
1207
/*
1208
 * plain contains an entire mime object.  Sign it and return an
1209
 * GpgmeData object with the signature of it or NULL in case of error.
1210
 * micalg returns the micalg information about the signature.
1211
 */
1212
static gpgme_data_t pgp_sign(gpgme_data_t plain, GSList *key_list,
1213
                             gboolean clearsign, gchar **micalg)
1214
{
1215
        GSList *p;
1216
        gpgme_ctx_t ctx = NULL;
1217
        gpgme_error_t err;
1218
        gpgme_data_t sig = NULL;
1219
        gpgme_sign_result_t result = NULL;
1220
        struct passphrase_cb_info_s info;
1221
1222
        *micalg = NULL;
1223
        memset(&info, 0, sizeof info);
1224
1225
        err = gpgme_new(&ctx);
1226
        if (err)
1227
                goto leave;
1228
        err = gpgme_data_new(&sig);
1229
        if (err)
1230
                goto leave;
1231
1232
        if (!g_getenv("GPG_AGENT_INFO")) {
1233
                info.c = ctx;
1234
                gpgme_set_passphrase_cb(ctx, gpgmegtk_passphrase_cb, &info);
1235
        }
1236
        gpgme_set_textmode(ctx, 1);
1237
        gpgme_set_armor(ctx, 1);
1238
        gpgme_signers_clear(ctx);
1239
        for (p = key_list; p != NULL; p = p->next) {
1240
                err = gpgme_signers_add(ctx, (gpgme_key_t) p->data);
1241
                if (err)
1242
                        goto leave;
1243
        }
1244
        for (p = key_list; p != NULL; p = p->next)
1245
                gpgme_key_unref((gpgme_key_t) p->data);
1246
        g_slist_free(key_list);
1247
1248
        err = (gpgme_data_seek(plain, 0, SEEK_SET) == -1) ?
1249
                gpgme_error_from_errno(errno) : 0;
1250
        if (!err) {
1251
                err = gpgme_op_sign(ctx, plain, sig,
1252
                                    clearsign ? GPGME_SIG_MODE_CLEAR : GPGME_SIG_MODE_DETACH);
1253
        }
1254
        if (!err) {
1255
                result = gpgme_op_sign_result(ctx);
1256
                if (result && result->signatures) {
1257
                        if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
1258
                                *micalg = g_strdup_printf
1259
                                        ("PGP-%s", gpgme_hash_algo_name(result->signatures->hash_algo));
1260
                        } else {
1261
                                *micalg = g_strdup(gpgme_hash_algo_name(result->signatures->hash_algo));
1262
                        }
1263
                } else {
1264
                        /* can't get result (maybe no signing key?) */
1265
                        err = GPG_ERR_USER_1;
1266
                }
1267
        }
1268
1269
leave:
1270
        if (err) {
1271
                gpgmegtk_free_passphrase();
1272
                g_warning("pgp_sign(): signing failed: %s\n", gpgme_strerror(err));
1273
                gpgme_data_release(sig);
1274
                sig = NULL;
1275
        } else {
1276
                debug_print("signing succeeded\n");
1277
        }
1278
1279
        gpgme_release(ctx);
1280
        return sig;
1281
}
1282
1283
/*
1284
 * plain contains an entire mime object.  Encrypt and sign it and return an
1285
 * GpgmeData object with the encrypted and signed version of it or NULL in
1286
 * case of error.
1287
 * micalg returns the micalg information about the signature.
1288
 */
1289
static gpgme_data_t pgp_encrypt_sign(gpgme_data_t plain, gpgme_key_t kset[],
1290
                                     GSList *key_list, gchar **micalg)
1291
{
1292
        GSList *p;
1293
        gpgme_ctx_t ctx = NULL;
1294
        gpgme_error_t err;
1295
        gpgme_data_t cipher = NULL;
1296
        gpgme_sign_result_t result = NULL;
1297
        struct passphrase_cb_info_s info;
1298
1299
        *micalg = NULL;
1300
        memset(&info, 0, sizeof info);
1301
1302
        err = gpgme_new(&ctx);
1303
        if (err)
1304
                goto leave;
1305
        err = gpgme_data_new(&cipher);
1306
        if (err)
1307
                goto leave;
1308
1309
        if (!g_getenv("GPG_AGENT_INFO")) {
1310
                info.c = ctx;
1311
                gpgme_set_passphrase_cb(ctx, gpgmegtk_passphrase_cb, &info);
1312
        }
1313
        gpgme_set_textmode(ctx, 1);
1314
        gpgme_set_armor(ctx, 1);
1315
        gpgme_signers_clear(ctx);
1316
        for (p = key_list; p != NULL; p = p->next) {
1317
                err = gpgme_signers_add(ctx, (gpgme_key_t) p->data);
1318
                if (err)
1319
                        goto leave;
1320
        }
1321
        for (p = key_list; p != NULL; p = p->next)
1322
                gpgme_key_unref((gpgme_key_t) p->data);
1323
        g_slist_free(key_list);
1324
1325
        err = (gpgme_data_seek(plain, 0, SEEK_SET) == -1) ?
1326
                gpgme_error_from_errno(errno) : 0;
1327
        if (!err) {
1328
                err = gpgme_op_encrypt_sign(ctx, kset, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher);
1329
        }
1330
        if (!err) {
1331
                result = gpgme_op_sign_result(ctx);
1332
                if (result && result->signatures) {
1333
                        if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
1334
                                *micalg = g_strdup_printf
1335
                                        ("PGP-%s", gpgme_hash_algo_name(result->signatures->hash_algo));
1336
                        } else {
1337
                                *micalg = g_strdup(gpgme_hash_algo_name(result->signatures->hash_algo));
1338
                        }
1339
                } else {
1340
                        /* can't get result (maybe no signing key?) */
1341
                        err = GPG_ERR_USER_1;
1342
                }
1343
        }
1344
1345
leave:
1346
        if (err) {
1347
                gpgmegtk_free_passphrase();
1348
                g_warning("pgp_sign(): encryption and signing failed: %s\n", gpgme_strerror(err));
1349
                gpgme_data_release(cipher);
1350
                cipher = NULL;
1351
        } else {
1352
                debug_print("encryption and signing succeeded\n");
1353
        }
1354
1355
        gpgme_release(ctx);
1356
        return cipher;
1357
}
1358
1359
/*
1360
 * Sign the file and replace its content with the signed one.
1361
 */
1362
gint rfc2015_sign(const gchar *file, GSList *key_list)
1363
{
1364
        FILE *fp = NULL;
1365
        gchar buf[BUFFSIZE];
1366
        gint i, clineidx, saved_last;
1367
        gchar *clines[3] = {NULL};
1368
        gpgme_error_t err;
1369
        gpgme_data_t header = NULL;
1370
        gpgme_data_t plain = NULL;
1371
        gpgme_data_t sigdata = NULL;
1372
        ssize_t bytesRW = -1;
1373
        gint mime_version_seen = 0;
1374
        gchar *boundary;
1375
        gchar *micalg = NULL;
1376
1377
        boundary = generate_mime_boundary("Signature");
1378
1379
        /* Open the source file */
1380
        if ((fp = g_fopen(file, "rb")) == NULL) {
1381
                FILE_OP_ERROR(file, "fopen");
1382
                goto failure;
1383
        }
1384
1385
        err = gpgme_data_new(&header);
1386
        if (!err)
1387
                err = gpgme_data_new(&plain);
1388
        if (err) {
1389
                debug_print("gpgme_data_new failed: %s\n", gpgme_strerror(err));
1390
                goto failure;
1391
        }
1392
1393
        /* get the content header lines from the source */
1394
        clineidx = 0;
1395
        saved_last = 0;
1396
        while (!err && fgets(buf, sizeof(buf), fp)) {
1397
                /* fixme: check for overlong lines */
1398
                if (headerp(buf, content_names)) {
1399
                        if (clineidx >= DIM(clines)) {
1400
                                debug_print("rfc2015_sign: too many content lines\n");
1401
                                goto failure;
1402
                        }
1403
                        clines[clineidx++] = g_strdup(buf);
1404
                        saved_last = 1;
1405
                        continue;
1406
                }
1407
                if (saved_last) {
1408
                        if (*buf == ' ' || *buf == '\t') {
1409
                                gchar *last = clines[clineidx - 1];
1410
                                clines[clineidx - 1] = g_strconcat(last, buf, NULL);
1411
                                g_free(last);
1412
                                continue;
1413
                        }
1414
                        saved_last = 0;
1415
                }
1416
1417
                if (headerp(buf, mime_version_name))
1418
                        mime_version_seen = 1;
1419
1420
                if (buf[0] == '\r' || buf[0] == '\n')
1421
                        break;
1422
                bytesRW = gpgme_data_write(header, buf, strlen (buf));
1423
        }
1424
        if (ferror (fp)) {
1425
                FILE_OP_ERROR(file, "fgets");
1426
                goto failure;
1427
        }
1428
1429
        /* write them to the temp data and add the rest of the message */
1430
        for (i = 0; (bytesRW != -1) && i < clineidx; i++) {
1431
                bytesRW = gpgme_data_write(plain, clines[i], strlen(clines[i]));
1432
        }
1433
        if (bytesRW != -1)
1434
                bytesRW = gpgme_data_write(plain, "\r\n", 2 );
1435
        while ((bytesRW != -1) && fgets(buf, sizeof(buf), fp)) {
1436
                bytesRW = gpgme_data_write(plain, buf, strlen(buf));
1437
        }
1438
        if (ferror(fp)) {
1439
                FILE_OP_ERROR(file, "fgets");
1440
                goto failure;
1441
        }
1442
        if (bytesRW == -1) {
1443
                debug_print("gpgme_data_write failed: %s\n",
1444
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1445
                goto failure;
1446
        }
1447
1448
        sigdata = pgp_sign(plain, key_list, FALSE, &micalg);
1449
        if (!sigdata)
1450
                goto failure;
1451
1452
        /* we have the signed message available in sigdata and now we are
1453
         * going to rewrite the original file. To be sure that file has
1454
         * been truncated we use an approach which should work everywhere:
1455
         * close the file and then reopen it for writing. */
1456
        if (fclose(fp)) {
1457
                FILE_OP_ERROR(file, "fclose");
1458
                goto failure;
1459
        }
1460
        if ((fp = g_fopen(file, "wb")) == NULL) {
1461
                FILE_OP_ERROR(file, "fopen");
1462
                goto failure;
1463
        }
1464
1465
        /* Write the rfc822 header and add new content lines */
1466
        err = (gpgme_data_seek(header, 0, SEEK_SET) == -1) ?
1467
                gpgme_error_from_errno(errno) : 0;
1468
        if (err)
1469
                debug_print("gpgme_data_seek failed: %s\n",
1470
                            gpgme_strerror(err));
1471
        bytesRW = gpgme_data_read(header, buf, BUFFSIZE);
1472
        while (bytesRW > 0) {
1473
                fwrite(buf, bytesRW, 1, fp);
1474
                bytesRW = gpgme_data_read(header, buf, BUFFSIZE);
1475
        }
1476
        if (bytesRW != 0) {
1477
                debug_print("gpgme_data_read failed: %s\n",
1478
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1479
                goto failure;
1480
        }
1481
        if (ferror(fp)) {
1482
                FILE_OP_ERROR(file, "fwrite");
1483
                goto failure;
1484
        }
1485
        gpgme_data_release(header);
1486
        header = NULL;
1487
1488
        if (!mime_version_seen)
1489
                fputs("MIME-Version: 1.0\r\n", fp);
1490
        fprintf(fp, "Content-Type: multipart/signed; "
1491
                "protocol=\"application/pgp-signature\";\r\n");
1492
        if (micalg)
1493
                fprintf(fp, " micalg=\"%s\";\r\n", micalg);
1494
        fprintf(fp, " boundary=\"%s\"\r\n", boundary);
1495
1496
        /* Part 1: signed material */
1497
        fprintf(fp, "\r\n"
1498
                "--%s\r\n",
1499
                boundary);
1500
        err = (gpgme_data_seek(plain, 0, SEEK_SET) == -1) ?
1501
                gpgme_error_from_errno(errno) : 0;
1502
        if (err) {
1503
                debug_print("gpgme_data_seek on plain failed: %s\n",
1504
                            gpgme_strerror(err));
1505
                goto failure;
1506
        }
1507
        bytesRW = gpgme_data_read(plain, buf, BUFFSIZE);
1508
        while (bytesRW > 0) {
1509
                fwrite(buf, bytesRW, 1, fp);
1510
                bytesRW = gpgme_data_read(plain, buf, BUFFSIZE);
1511
        }
1512
        if (bytesRW != 0) {
1513
                debug_print("gpgme_data_read failed: %s\n",
1514
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1515
                goto failure;
1516
        }
1517
1518
        /* Part 2: signature */
1519
        fprintf(fp, "\r\n"
1520
                "--%s\r\n",
1521
                boundary);
1522
        fputs("Content-Type: application/pgp-signature\r\n"
1523
              "\r\n", fp);
1524
1525
        err = (gpgme_data_seek(sigdata, 0, SEEK_SET) == -1) ?
1526
                gpgme_error_from_errno(errno) : 0;
1527
        if (err) {
1528
                debug_print("gpgme_data_seek on sigdata failed: %s\n",
1529
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1530
                goto failure;
1531
        }
1532
1533
        bytesRW = gpgme_data_read(sigdata, buf, BUFFSIZE);
1534
        while (bytesRW > 0) {
1535
                fwrite(buf, bytesRW, 1, fp);
1536
                bytesRW = gpgme_data_read(sigdata, buf, BUFFSIZE);
1537
        }
1538
        if (bytesRW != 0) {
1539
                debug_print("gpgme_data_read failed: %s\n",
1540
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1541
                goto failure;
1542
        }
1543
1544
        /* Final boundary */
1545
        fprintf(fp, "\r\n"
1546
                "--%s--\r\n",
1547
                boundary);
1548
        fflush(fp);
1549
        if (ferror(fp)) {
1550
                FILE_OP_ERROR(file, "fwrite");
1551
                goto failure;
1552
        }
1553
        fclose(fp);
1554
        gpgme_data_release(header);
1555
        gpgme_data_release(plain);
1556
        gpgme_data_release(sigdata);
1557
        g_free(boundary);
1558
        g_free(micalg);
1559
        return 0;
1560
1561
failure:
1562
        if (fp)
1563
                fclose(fp);
1564
        gpgme_data_release(header);
1565
        gpgme_data_release(plain);
1566
        gpgme_data_release(sigdata);
1567
        g_free(boundary);
1568
        g_free(micalg);
1569
        return -1; /* error */
1570
}
1571
1572
1573
/*
1574
 * Sign the file with clear text and replace its content with the signed one.
1575
 */
1576
gint rfc2015_clearsign(const gchar *file, GSList *key_list)
1577
{
1578
        FILE *fp;
1579
        gchar buf[BUFFSIZE];
1580
        gpgme_error_t err;
1581
        gpgme_data_t text = NULL;
1582
        gpgme_data_t sigdata = NULL;
1583
        ssize_t bytesRW = 0;
1584
        gchar *micalg = NULL;
1585
1586
        if ((fp = g_fopen(file, "rb")) == NULL) {
1587
                FILE_OP_ERROR(file, "fopen");
1588
                goto failure;
1589
        }
1590
1591
        err = gpgme_data_new(&text);
1592
        if (err) {
1593
                debug_print("gpgme_data_new failed: %s\n", gpgme_strerror(err));
1594
                goto failure;
1595
        }
1596
1597
        while ((bytesRW != -1) && fgets(buf, sizeof(buf), fp)) {
1598
                bytesRW = gpgme_data_write(text, buf, strlen(buf));
1599
        }
1600
        if (ferror(fp)) {
1601
                FILE_OP_ERROR(file, "fgets");
1602
                goto failure;
1603
        }
1604
        if (bytesRW == -1) {
1605
                debug_print("gpgme_data_write failed: %s\n",
1606
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1607
                goto failure;
1608
        }
1609
1610
        sigdata = pgp_sign(text, key_list, TRUE, &micalg);
1611
        if (micalg) {
1612
                g_free(micalg);
1613
        }
1614
        if (!sigdata)
1615
                goto failure;
1616
1617
        if (fclose(fp) == EOF) {
1618
                FILE_OP_ERROR(file, "fclose");
1619
                fp = NULL;
1620
                goto failure;
1621
        }
1622
        if ((fp = g_fopen(file, "wb")) == NULL) {
1623
                FILE_OP_ERROR(file, "fopen");
1624
                goto failure;
1625
        }
1626
1627
        err = (gpgme_data_seek(sigdata, 0, SEEK_SET) == -1) ?
1628
                gpgme_error_from_errno(errno) : 0;
1629
        if (err) {
1630
                debug_print("gpgme_data_seek on sigdata failed: %s\n",
1631
                            gpgme_strerror(err));
1632
                goto failure;
1633
        }
1634
1635
        bytesRW = gpgme_data_read(sigdata, buf, BUFFSIZE);
1636
        while (bytesRW > 0) {
1637
                fwrite(buf, bytesRW, 1, fp);
1638
                bytesRW = gpgme_data_read(sigdata, buf, BUFFSIZE);
1639
        }
1640
        if (bytesRW != 0) {
1641
                debug_print("gpgme_data_read failed: %s\n",
1642
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1643
                goto failure;
1644
        }
1645
1646
        if (fclose(fp) == EOF) {
1647
                FILE_OP_ERROR(file, "fclose");
1648
                fp = NULL;
1649
                goto failure;
1650
        }
1651
        gpgme_data_release(text);
1652
        gpgme_data_release(sigdata);
1653
        return 0;
1654
1655
failure:
1656
        if (fp)
1657
                fclose(fp);
1658
        gpgme_data_release(text);
1659
        gpgme_data_release(sigdata);
1660
        return -1;
1661
}
1662
1663
gint rfc2015_encrypt_sign_armored(const gchar *file, GSList *recp_list,
1664
                                  GSList *key_list)
1665
{
1666
        FILE *fp;
1667
        gchar buf[BUFFSIZE];
1668
        gint i;
1669
        gpgme_error_t err;
1670
        gpgme_data_t plain = NULL;
1671
        gpgme_data_t cipher = NULL;
1672
        gpgme_key_t *kset = NULL;
1673
        ssize_t bytesRW = 0;
1674
        gchar *micalg = NULL;
1675
1676
        kset = gpgmegtk_recipient_selection(recp_list);
1677
        if (!kset) {
1678
                debug_print("error creating recipient list\n");
1679
                goto failure;
1680
        }
1681
1682
        if ((fp = g_fopen(file, "rb")) == NULL) {
1683
                FILE_OP_ERROR(file, "fopen");
1684
                goto failure;
1685
        }
1686
1687
        err = gpgme_data_new(&plain);
1688
        if (err) {
1689
                debug_print("gpgme_data_new failed: %s\n", gpgme_strerror(err));
1690
                goto failure;
1691
        }
1692
1693
        while ((bytesRW != -1) && fgets(buf, sizeof(buf), fp)) {
1694
                bytesRW = gpgme_data_write(plain, buf, strlen(buf));
1695
        }
1696
        if (ferror(fp)) {
1697
                FILE_OP_ERROR(file, "fgets");
1698
                goto failure;
1699
        }
1700
        if (bytesRW == -1) {
1701
                debug_print("gpgme_data_write failed: %s\n",
1702
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1703
                goto failure;
1704
        }
1705
1706
        cipher = pgp_encrypt_sign(plain, kset, key_list, &micalg);
1707
        if (micalg)
1708
                g_free(micalg);
1709
        if (!cipher)
1710
                goto failure;
1711
1712
        if (fclose(fp) == EOF) {
1713
                FILE_OP_ERROR(file, "fclose");
1714
                fp = NULL;
1715
                goto failure;
1716
        }
1717
        if ((fp = g_fopen(file, "wb")) == NULL) {
1718
                FILE_OP_ERROR(file, "fopen");
1719
                goto failure;
1720
        }
1721
1722
        err = (gpgme_data_seek(cipher, 0, SEEK_SET) == -1) ?
1723
                gpgme_error_from_errno(errno) : 0;
1724
        if (err) {
1725
                debug_print("gpgme_data_seek on cipher failed: %s\n",
1726
                            gpgme_strerror(err));
1727
                goto failure;
1728
        }
1729
1730
        bytesRW = gpgme_data_read(cipher, buf, BUFFSIZE);
1731
        while (bytesRW > 0) {
1732
                fwrite(buf, bytesRW, 1, fp);
1733
                bytesRW = gpgme_data_read(cipher, buf, BUFFSIZE);
1734
        }
1735
        if (bytesRW != 0) {
1736
                debug_print("gpgme_data_read failed: %s\n",
1737
                            gpgme_strerror(gpgme_error_from_errno(errno)));
1738
                goto failure;
1739
        }
1740
1741
        if (fclose(fp) == EOF) {
1742
                FILE_OP_ERROR(file, "fclose");
1743
                fp = NULL;
1744
                goto failure;
1745
        }
1746
        gpgme_data_release(plain);
1747
        gpgme_data_release(cipher);
1748
        for (i = 0; kset[i] != NULL; i++)
1749
                gpgme_key_unref(kset[i]);
1750
        return 0;
1751
1752
failure:
1753
        if (fp)
1754
                fclose(fp);
1755
        gpgme_data_release(plain);
1756
        gpgme_data_release(cipher);
1757
        if (kset != NULL) {
1758
                for (i = 0; kset[i] != NULL; i++)
1759
                        gpgme_key_unref(kset[i]);
1760
        }
1761
        return -1;
1762
}
1763
1764
#endif /* USE_GPGME */