summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2009-12-08 20:08:36 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2009-12-08 20:11:04 (GMT)
commit67ca2ef061a73bc90e4399471ee0cb3ce6f0ee41 (patch) (side-by-side diff)
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.
Diffstat (more/less context) (ignore whitespace changes)
-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
@@ -99,6 +99,15 @@ check-unrevised:
rm $@-t; \
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
check-docs:
diff --git a/src/config.c b/src/config.c
index 559f766..f0a7042 100644
--- a/src/config.c
+++ b/src/config.c
@@ -863,6 +863,9 @@ static struct grecs_keyword mail_statistics_kw[] = {
{ "statistics",
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 }
};
@@ -907,6 +910,9 @@ static struct grecs_keyword notify_event_kw[] = {
{ "message", N_("text-or-id"),
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 }
};
@@ -1456,6 +1462,9 @@ 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
@@ -128,8 +128,8 @@ remove_homedir ()
}
/* Create a temporary GPG home directory */
-int
-wydawca_gpg_homedir ()
+static int
+create_gpg_homedir ()
{
if (homedir)
return 0;
@@ -222,12 +222,11 @@ 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));
for (uptr = trp->uploader_list; uptr; uptr = uptr->next)
@@ -301,7 +300,7 @@ verify_detached_signature (struct file_triplet *trp,
return 1;
}
- wydawca_gpg_homedir ();
+ create_gpg_homedir ();
argv[0] = info->file_name;
argv[1] = "--verify";
argv[2] = trp->file[file_signature].name;
diff --git a/src/mail.c b/src/mail.c
index 91ea502..15c2937 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -17,6 +17,7 @@
#include "wydawca.h"
#include <mail.h>
#include <hash.h>
+#include <gpgme.h>
int mailer_opened;
mu_mailer_t mailer;
@@ -27,6 +28,7 @@ unsigned long owner_notification_flags;
char *user_message_template[MAX_EVENT];
char *admin_stat_message;
+char *admin_stat_sign_key;
void
mail_init ()
@@ -44,8 +46,203 @@ 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;
mu_message_t msg;
@@ -91,7 +288,7 @@ mail_send_message (mu_address_t rcpt, const char *text)
if (debug_level > 2)
mailer_flags = MAILER_FLAG_DEBUG_DATA;
}
-
+
if (!mailer_opened)
{
if ((rc = mu_mailer_open (mailer, mailer_flags)))
@@ -106,10 +303,16 @@ mail_send_message (mu_address_t rcpt, const char *text)
mailer_opened = 1;
}
- 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));
}
@@ -244,9 +447,6 @@ mail_stats ()
free (buf);
}
- if (dry_run_mode)
- return;
-
tc = timer_get_count () * 3;
exp = make_stat_expansion (tc + 1);
time (&t);
@@ -264,7 +464,7 @@ 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);
meta_free (exp);
@@ -366,6 +566,8 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
{
mu_address_t rcpt = NULL;
const char *errp;
+ const char *msg;
+
switch (ntf->tgt)
{
case notify_read:
@@ -408,21 +610,19 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
free (buf);
}
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);
}
mu_address_destroy (&rcpt);
diff --git a/src/wydawca.c b/src/wydawca.c
index 07cac5c..f098bb1 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -45,6 +45,7 @@ int foreground;
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
@@ -281,6 +281,7 @@ struct notification
struct notification *next;
enum notification_event ev;
enum notification_target tgt;
+ const char *sign_keys;
const char *msg;
};
@@ -327,6 +328,7 @@ extern unsigned long print_stats;
extern int archive_signatures;
extern char *admin_stat_message;
+extern char *admin_stat_sign_key;
extern char *pidfile;
extern int force_startup;
@@ -344,6 +346,8 @@ 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.