Statistics
| Revision:

root / src / rfc2015.c @ 92

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