aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-12-08 22:08:36 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-12-08 22:11:04 +0200
commit67ca2ef061a73bc90e4399471ee0cb3ce6f0ee41 (patch)
treed45493df75f3f613ca6b3d13a7f5d7a0280650a6
parente1afd42340c0b2c22660744e0f88258a44617e88 (diff)
downloadwydawca-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.
-rw-r--r--doc/Makefile.am9
-rw-r--r--src/config.c9
-rw-r--r--src/gpg.c9
-rw-r--r--src/mail.c244
-rw-r--r--src/wydawca.c1
-rw-r--r--src/wydawca.h4
6 files changed, 249 insertions, 27 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f53e47c..721ea29 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -100,4 +100,13 @@ check-unrevised:
fi
+check-config:
+ @check-docs.sh 'configuration statements' \
+ '/wydawca_keywords\[\] *= *{/,/^}/s/[ \t]*{ *"\([^,"]*\)".*/\1/pg' \
+ 's/@deffnx\{0,1\} {Config} *\([^@,]*\).*/\1/p' \
+ $(top_srcdir)/src/config.c -- \
+ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) -E - \
+ $(info_TEXINFOS)
+
+
all-check-docs: check-format check-options check-refs check-fixmes check-unrevised check-writeme
diff --git a/src/config.c b/src/config.c
index 559f766..f0a7042 100644
--- a/src/config.c
+++ b/src/config.c
@@ -864,4 +864,7 @@ static struct grecs_keyword mail_statistics_kw[] = {
N_("items"), N_("Send mail if one or more of these items are set"),
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 }
};
@@ -908,4 +911,7 @@ static struct grecs_keyword notify_event_kw[] = {
N_("Text of the notification or identifier of a defined message template"),
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 }
};
@@ -1457,4 +1463,7 @@ static struct grecs_keyword wydawca_kw[] = {
{ "all-spools", NULL, N_("Service names that request scanning all spools"),
grecs_type_string|GRECS_LIST, &all_spool_aliases },
+
+ { "gpg-homedir", NULL, N_("GPG home directory"),
+ grecs_type_string, &wydawca_gpg_homedir },
{ NULL }
diff --git a/src/gpg.c b/src/gpg.c
index 71be53c..1389845 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -129,6 +129,6 @@ remove_homedir ()
/* Create a temporary GPG home directory */
-int
-wydawca_gpg_homedir ()
+static int
+create_gpg_homedir ()
{
if (homedir)
@@ -223,10 +223,9 @@ verify_directive_signature (struct file_triplet *trp,
gpgme_ctx_t ctx;
gpgme_data_t key_data, directive_data, plain;
- off_t size;
gpgme_error_t ec;
int rc;
struct uploader_info *uptr;
- wydawca_gpg_homedir ();
+ create_gpg_homedir ();
fail_if_err (gpgme_new (&ctx));
@@ -302,5 +301,5 @@ verify_detached_signature (struct file_triplet *trp,
}
- wydawca_gpg_homedir ();
+ create_gpg_homedir ();
argv[0] = info->file_name;
argv[1] = "--verify";
diff --git a/src/mail.c b/src/mail.c
index 91ea502..15c2937 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -18,4 +18,5 @@
#include <mail.h>
#include <hash.h>
+#include <gpgme.h>
int mailer_opened;
@@ -28,4 +29,5 @@ char *user_message_template[MAX_EVENT];
char *admin_stat_message;
+char *admin_stat_sign_key;
void
@@ -45,6 +47,201 @@ 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)
{
int rc;
@@ -92,5 +289,5 @@ mail_send_message (mu_address_t rcpt, const char *text)
mailer_flags = MAILER_FLAG_DEBUG_DATA;
}
-
+
if (!mailer_opened)
{
@@ -107,8 +304,14 @@ 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));
}
@@ -245,7 +448,4 @@ mail_stats ()
}
- if (dry_run_mode)
- return;
-
tc = timer_get_count () * 3;
exp = make_stat_expansion (tc + 1);
@@ -265,5 +465,5 @@ mail_stats ()
text = meta_expand_string (tmpl, exp, NULL, NULL, NULL);
- mail_send_message (admin_address, text);
+ mail_send_message (admin_address, text, admin_stat_sign_key);
free (text);
@@ -367,4 +567,6 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
mu_address_t rcpt = NULL;
const char *errp;
+ const char *msg;
+
switch (ntf->tgt)
{
@@ -409,19 +611,17 @@ 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
@@ -46,4 +46,5 @@ int single_process;
time_t wakeup_interval;
gl_list_t all_spool_aliases;
+char *wydawca_gpg_homedir;
struct grecs_sockaddr listen_sockaddr;
diff --git a/src/wydawca.h b/src/wydawca.h
index 805b72b..96fd336 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -282,4 +282,5 @@ struct notification
enum notification_event ev;
enum notification_target tgt;
+ const char *sign_keys;
const char *msg;
};
@@ -328,4 +329,5 @@ extern int archive_signatures;
extern char *admin_stat_message;
+extern char *admin_stat_sign_key;
extern char *pidfile;
@@ -345,4 +347,6 @@ extern struct grecs_sockaddr listen_sockaddr;
extern gl_list_t all_spool_aliases;
+extern char *wydawca_gpg_homedir;
+
#define UPDATE_STATS(what) \
do \

Return to:

Send suggestions and report system problems to the System administrator.