Browse Source

Implement encryption only.

Allow the use of -E option to specify a recipient to encrypt the
message to. If several -E options are used, the message will be
encrypted to all specified recipients.
develop
Damien Goutte-Gattat 3 years ago
parent
commit
03d5348f49
  1. 121
      src/fmail.c

121
src/fmail.c

@ -114,6 +114,8 @@ typedef struct fmail_ctx
{
const char **attachments;
size_t att_count;
const char **recipients;
size_t rcp_count;
const char *footer;
magic_t magic_ctx;
gpgme_ctx_t crypto_ctx;
@ -300,7 +302,7 @@ process_text_body(fmail_ctx_t *ctx, FILE *out)
/* Signing stuff. */
/* Crypto stuff. */
gpgme_ctx_t
initialize_gpgme(void)
@ -402,6 +404,99 @@ sign_stream(gpgme_ctx_t ctx, FILE *in, FILE *out)
gpgme_data_release(gout);
}
static gpgme_key_t *
get_recipient_keys(gpgme_ctx_t ctx, const char **recipients, size_t nr)
{
gpgme_key_t *keys, key;
gpgme_error_t gerr;
int i, j;
keys = NULL;
for ( i = j = gerr = 0; i < nr && ! gerr ; i++ ) {
gerr = gpgme_op_keylist_start (ctx, recipients[i], 0);
while ( ! gerr ) {
gerr = gpgme_op_keylist_next (ctx, &key);
if ( gerr )
break;
if ( j % 10 == 0 )
keys = xrealloc(keys, j + 10);
keys[j++] = key;
}
if ( gpgme_err_code(gerr) == GPG_ERR_EOF )
gerr = 0;
}
if ( gerr != 0 && gpgme_err_code(gerr) != GPG_ERR_EOF)
errx(EXIT_FAILURE, "cannot get recipient keys: %s", gpgme_strerror(gerr));
/* GpgME expects a NULL-terminated array of keys. */
if ( j % 10 == 0 )
keys = xrealloc(keys, j + 1);
keys[j++] = NULL;
return keys;
}
static void
encrypt_stream(gpgme_ctx_t ctx,
FILE *in,
FILE *out,
const char **recipients,
size_t nr)
{
gpgme_data_t gin, gout;
gpgme_key_t *keys, *key;
gpgme_error_t gerr;
char boundary[32], buffer[512];
int n;
keys = get_recipient_keys(ctx, recipients, nr);
gpgme_data_new_from_stream(&gin, in);
gpgme_data_new(&gout);
gerr = gpgme_op_encrypt(ctx, keys, 0, gin, gout);
if ( gerr != GPG_ERR_NO_ERROR )
errx(EXIT_FAILURE, "encrypting failed: %s", gpgme_strerror(gerr));
generate_boundary(boundary, sizeof(boundary));
fprintf(out, "Content-Type: multipart/encrypted;\r\n"
" boundary=\"%s\";\r\n"
" protocol=\"application/pgp-encrypted\r\n"
"\r\n"
"--%s\r\n"
"Content-Type: application/pgp-encrypted\r\n"
"\r\n"
"Version: 1\r\n"
"\r\n"
"--%s\r\n"
"Content-Type: application/octet-stream\r\n"
"\r\n",
boundary, boundary, boundary);
gpgme_data_seek(gout, 0, SEEK_SET);
while ( (n = gpgme_data_read(gout, buffer, sizeof(buffer))) > 0 ) {
int i = 0;
while ( i < n ) {
if ( buffer[i] == '\n' )
fputc('\r', out);
fputc(buffer[i], out);
i += 1;
}
}
fprintf(out, "\r\n--%s--\r\n", boundary);
gpgme_data_release(gin);
gpgme_data_release(gout);
for ( key = keys; *key != NULL; key++ )
gpgme_key_release(*key);
free(keys);
}
/* Attachments stuff. */
@ -535,7 +630,7 @@ main(int argc, char *argv[])
char c, with_useragent, with_date;
string_buffer_t *headers;
fmail_ctx_t ctx;
int do_sign, do_encrypt;
int do_sign;
struct option options[] = {
{ "help", 0, NULL, 'h' },
@ -559,13 +654,15 @@ main(int argc, char *argv[])
setlocale(LC_ALL, "");
srand(time(NULL));
with_useragent = with_date = do_sign = do_encrypt = 0;
with_useragent = with_date = do_sign = 0;
headers = sb_new(0);
ctx.crypto_ctx = NULL;
ctx.magic_ctx = initialize_magic();
ctx.attachments = NULL;
ctx.att_count = 0;
ctx.recipients = NULL;
ctx.rcp_count = 0;
ctx.footer = NULL;
ctx.input = stdin;
@ -589,7 +686,9 @@ main(int argc, char *argv[])
break;
case 'E':
do_encrypt = 1;
if ( ctx.rcp_count % 10 == 0 )
ctx.recipients = xrealloc(ctx.recipients, ctx.rcp_count + 10);
ctx.recipients[ctx.rcp_count++] = optarg;
break;
case 'a':
@ -636,9 +735,9 @@ main(int argc, char *argv[])
}
}
if ( do_sign && do_encrypt )
if ( do_sign && ctx.rcp_count )
errx(EXIT_FAILURE, "encrypt and sign is not currently supported");
if ( do_sign || do_encrypt )
if ( do_sign || ctx.rcp_count )
ctx.crypto_ctx = initialize_gpgme();
/* Generate automatic headers */
@ -657,12 +756,15 @@ main(int argc, char *argv[])
/* Write all headers. */
fprintf(stdout, "%s", sb_get(headers));
if ( do_sign ) {
if ( do_sign || ctx.rcp_count ) {
FILE *tmp = tmpfile();
process_text_body(&ctx, tmp);
fseek(tmp, 0, SEEK_SET);
sign_stream(ctx.crypto_ctx, tmp, stdout);
if ( do_sign )
sign_stream(ctx.crypto_ctx, tmp, stdout);
else
encrypt_stream(ctx.crypto_ctx, tmp, stdout, ctx.recipients, ctx.rcp_count);
fclose(tmp);
gpgme_release(ctx.crypto_ctx);
@ -675,6 +777,9 @@ main(int argc, char *argv[])
if ( ctx.attachments )
free(ctx.attachments);
if ( ctx.recipients )
free(ctx.recipients);
magic_close(ctx.magic_ctx);
return EXIT_SUCCESS;

Loading…
Cancel
Save