diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-12-08 22:08:36 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-12-08 22:11:04 +0200 |
commit | 67ca2ef061a73bc90e4399471ee0cb3ce6f0ee41 (patch) | |
tree | d45493df75f3f613ca6b3d13a7f5d7a0280650a6 /src | |
parent | e1afd42340c0b2c22660744e0f88258a44617e88 (diff) | |
download | wydawca-67ca2ef061a73bc90e4399471ee0cb3ce6f0ee41.tar.gz wydawca-67ca2ef061a73bc90e4399471ee0cb3ce6f0ee41.tar.bz2 |
Implement GPG signing of the outgoing notifications.
* src/config.c (mail_statistics_kw): New keyword gpg-sign.
(notify_event_kw): Likewise.
(wydawca_kw): New keyword gpg-homedir.
* src/gpg.c (wydawca_gpg_homedir): Rename to
create_gpg_homedir. Make static.
All uses updated.
* src/mail.c (admin_stat_sign_key): New global.
(mu_stream_data_read_cb)
(gpg_sign, sign_message): New functions.
(mail_send_message): Take 3rd argument: ID of
the PGP key to sign the message with.
All callers updated.
(do_notify): Rewrite.
* src/wydawca.c (wydawca_gpg_homedir): New variable.
* src/wydawca.h (struct notification): New member
sign_keys.
(admin_stat_sign_key): New extern.
(wydawca_gpg_homedir): New extern.
Diffstat (limited to 'src')
-rw-r--r-- | src/config.c | 9 | ||||
-rw-r--r-- | src/gpg.c | 9 | ||||
-rw-r--r-- | src/mail.c | 244 | ||||
-rw-r--r-- | src/wydawca.c | 1 | ||||
-rw-r--r-- | src/wydawca.h | 4 |
5 files changed, 240 insertions, 27 deletions
diff --git a/src/config.c b/src/config.c index 559f766..f0a7042 100644 --- a/src/config.c +++ b/src/config.c @@ -865,2 +865,5 @@ static struct grecs_keyword mail_statistics_kw[] = { grecs_type_string, &mail_admin_mask, 0, cb_statistics }, + { "gpg-sign", + N_("key"), N_("Sign message with this key"), + grecs_type_string, &admin_stat_sign_key }, { NULL } @@ -909,2 +912,5 @@ static struct grecs_keyword notify_event_kw[] = { grecs_type_string, NULL, offsetof(struct notification, msg) }, + { "gpg-sign", N_("key"), + N_("Sign message with this key"), + grecs_type_string, NULL, offsetof(struct notification, sign_keys) }, { NULL } @@ -1458,2 +1464,5 @@ static struct grecs_keyword wydawca_kw[] = { grecs_type_string|GRECS_LIST, &all_spool_aliases }, + + { "gpg-homedir", NULL, N_("GPG home directory"), + grecs_type_string, &wydawca_gpg_homedir }, @@ -130,4 +130,4 @@ remove_homedir () /* Create a temporary GPG home directory */ -int -wydawca_gpg_homedir () +static int +create_gpg_homedir () { @@ -224,3 +224,2 @@ verify_directive_signature (struct file_triplet *trp, gpgme_data_t key_data, directive_data, plain; - off_t size; gpgme_error_t ec; @@ -229,3 +228,3 @@ verify_directive_signature (struct file_triplet *trp, - wydawca_gpg_homedir (); + create_gpg_homedir (); fail_if_err (gpgme_new (&ctx)); @@ -303,3 +302,3 @@ verify_detached_signature (struct file_triplet *trp, - wydawca_gpg_homedir (); + create_gpg_homedir (); argv[0] = info->file_name; @@ -19,2 +19,3 @@ #include <hash.h> +#include <gpgme.h> @@ -29,2 +30,3 @@ char *user_message_template[MAX_EVENT]; char *admin_stat_message; +char *admin_stat_sign_key; @@ -46,4 +48,199 @@ mail_init () +struct mu_stream_handle +{ + mu_stream_t str; + mu_off_t off; +}; + +static ssize_t +mu_stream_data_read_cb (void *handle, void *buffer, size_t size) +{ + struct mu_stream_handle *mhp = handle; + size_t nread; + int rc; + + rc = mu_stream_read (mhp->str, buffer, size, mhp->off, &nread); + if (rc) + { + logmsg (LOG_ERR, "mu_stream_read: %s", mu_strerror (rc)); + errno = EIO; + return -1; + } + + mhp->off += nread; + return nread; +} + +static int +gpg_sign (gpgme_data_t *output, gpgme_data_t input, const char *sign_keys) +{ + gpgme_ctx_t ctx; + gpgme_error_t err = 0; + gpgme_key_t key; + + err = gpgme_new (&ctx); + if (err) + { + logmsg (LOG_ERR, _("GPGME: cannot create context: %s"), + gpgme_strerror (err)); + return 1; + } + + err = gpgme_op_keylist_start (ctx, sign_keys, 0); + if (!err) + { + while ((err = gpgme_op_keylist_next (ctx, &key)) == 0) + { + err = gpgme_signers_add (ctx, key); + gpgme_key_release (key); + } + } + + if (err && gpg_err_code (err) != GPG_ERR_EOF) + { + logmsg (LOG_ERR, _("GPGME: cannot list keys: %s"), + gpgme_strerror (err)); + gpgme_release (ctx); + return 1; + } + + err = gpgme_data_new (output); + if (err) + { + logmsg (LOG_ERR, _("%s: GPGME error: %s"), + "gpgme_data_new", + gpgme_strerror (err)); + gpgme_release (ctx); + return 1; + } + + /* FIXME: Passphrase */ + gpgme_set_textmode (ctx, 1); + gpgme_set_armor (ctx, 1); + + err = gpgme_op_sign (ctx, input, *output, GPGME_SIG_MODE_CLEAR); + if (err) + logmsg (LOG_ERR, _("%s: GPGME error: %s"), + "gpgme_op_sign", + gpgme_strerror (err)); +#if 0 + /* FIXME: */ + else if (debug_level > 1) + gpgme_debug_info (ctx); +#endif + + gpgme_release (ctx); + return err != 0; +} + +static int +sign_message (mu_message_t *pmsg, const char *key) +{ + mu_message_t msg = *pmsg; + mu_message_t newmsg; + mu_body_t body; + mu_header_t hdr; + struct mu_stream_handle mhn; + mu_stream_t istr, ostr; + int rc; + struct gpgme_data_cbs cbs; + gpgme_data_t input, output; + gpgme_error_t err; + char *buf = NULL; + size_t size = 0; + size_t nread; + + if (debug_level) + logmsg (LOG_DEBUG, _("signing message as %s"), key); + + if (wydawca_gpg_homedir) + { + if (debug_level > 1) + logmsg (LOG_DEBUG, _("setting GNUPG home directory: %s"), + wydawca_gpg_homedir); + setenv ("GNUPGHOME", wydawca_gpg_homedir, 1); + } + + if ((rc = mu_message_get_body (msg, &body))) + { + logmsg (LOG_ERR, "mu_message_get_body: %s", mu_strerror (rc)); + return 1; + } + + if ((rc = mu_body_get_stream (body, &mhn.str))) + { + logmsg (LOG_ERR, "mu_message_get_stream: %s", mu_strerror (rc)); + return 1; + } + + mu_stream_seek (mhn.str, 0, SEEK_SET); + mhn.off = 0; + + memset (&cbs, 0, sizeof (cbs)); + cbs.read = mu_stream_data_read_cb; + + err = gpgme_data_new_from_cbs (&input, &cbs, &mhn); + if (err) + { + logmsg (LOG_ERR, "gpgme_data_new_from_cbs: %s", + gpgme_strerror (rc)); + return 1; + } + + rc = gpg_sign (&output, input, key); + + if (gpgme_data_seek (output, 0, SEEK_SET) == -1) + { + logmsg (LOG_ERR, "gpgme_data_seek: %s", strerror (errno)); + return 1; + } + + mu_message_create (&newmsg, NULL); + mu_message_get_stream (newmsg, &ostr); + + /* Copy headers */ + mu_message_get_header (msg, &hdr); + mu_header_get_stream (hdr, &istr); + mu_stream_seek (istr, 0, SEEK_SET); + while ((rc = mu_stream_sequential_getline (istr, &buf, &size, &nread)) == 0 + && nread) + { + rc = mu_stream_sequential_write (ostr, buf, nread); + if (rc) + { + logmsg (LOG_ERR, "mu_stream_sequential_write: %s", + mu_strerror (rc)); + break; + } + } + + if (rc == 0) + { + while ((nread = gpgme_data_read (output, buf, size)) > 0) + { + rc = mu_stream_sequential_write (ostr, buf, nread); + if (rc) + { + logmsg (LOG_ERR, "mu_stream_sequential_write: %s", + mu_strerror (rc)); + break; + } + } + + if (rc == 0) + { + mu_message_destroy (&msg, mu_message_get_owner (msg)); + *pmsg = newmsg; + } + } + + gpgme_data_release (output); + free (buf); + + return rc; +} + void -mail_send_message (mu_address_t rcpt, const char *text) +mail_send_message (mu_address_t rcpt, const char *text, + const char *signer_key) { @@ -93,3 +290,3 @@ mail_send_message (mu_address_t rcpt, const char *text) } - + if (!mailer_opened) @@ -108,6 +305,12 @@ mail_send_message (mu_address_t rcpt, const char *text) - rc = mu_mailer_send_message (mailer, msg, from_address, rcpt); - if (rc) - logmsg (LOG_CRIT, _("cannot send message: %s"), mu_strerror (rc)); - + if (signer_key) + sign_message (&msg, signer_key); + + if (!dry_run_mode) + { + rc = mu_mailer_send_message (mailer, msg, from_address, rcpt); + if (rc) + logmsg (LOG_CRIT, _("cannot send message: %s"), mu_strerror (rc)); + } + mu_message_destroy (&msg, mu_message_get_owner (msg)); @@ -246,5 +449,2 @@ mail_stats () - if (dry_run_mode) - return; - tc = timer_get_count () * 3; @@ -266,3 +466,3 @@ mail_stats () - mail_send_message (admin_address, text); + mail_send_message (admin_address, text, admin_stat_sign_key); @@ -368,2 +568,4 @@ do_notify (struct file_triplet *trp, enum notification_event ev, const char *errp; + const char *msg; + switch (ntf->tgt) @@ -410,17 +612,15 @@ do_notify (struct file_triplet *trp, enum notification_event ev, else - logmsg (LOG_DEBUG, _("notifying message recipients (project %s) about %s"), + logmsg (LOG_DEBUG, + _("notifying message recipients (project %s) about %s"), trp->project, notification_event_str (ev)); } - - if (!dry_run_mode) + + msg = resolve_message_template (ntf->msg); + if (!msg) + logmsg (LOG_ERR, _("undefined message reference: %s"), ntf->msg); + else { - const char *msg = resolve_message_template (ntf->msg); - if (!msg) - logmsg (LOG_ERR, _("undefined message reference: %s"), ntf->msg); - else - { - char *text = triplet_expand_param (msg, trp); - mail_send_message (rcpt, text); - free (text); - } + char *text = triplet_expand_param (msg, trp); + mail_send_message (rcpt, text, ntf->sign_keys); + free (text); } diff --git a/src/wydawca.c b/src/wydawca.c index 07cac5c..f098bb1 100644 --- a/src/wydawca.c +++ b/src/wydawca.c @@ -47,2 +47,3 @@ time_t wakeup_interval; gl_list_t all_spool_aliases; +char *wydawca_gpg_homedir; diff --git a/src/wydawca.h b/src/wydawca.h index 805b72b..96fd336 100644 --- a/src/wydawca.h +++ b/src/wydawca.h @@ -283,2 +283,3 @@ struct notification enum notification_target tgt; + const char *sign_keys; const char *msg; @@ -329,2 +330,3 @@ extern int archive_signatures; extern char *admin_stat_message; +extern char *admin_stat_sign_key; @@ -346,2 +348,4 @@ extern gl_list_t all_spool_aliases; +extern char *wydawca_gpg_homedir; + #define UPDATE_STATS(what) \ |