Statistics
| Revision:

root / src / rfc2015.c @ 690

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