Statistics
| Revision:

root / src / rfc2015.c @ 332

History | View | Annotate | Download (34.9 kB)

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