aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
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
@@ -860,12 +860,15 @@ cb_archive (enum grecs_callback_command cmd,
static struct grecs_keyword mail_statistics_kw[] = {
{ "message", N_("text"), N_("Message text"),
grecs_type_string, &admin_stat_message },
{ "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 }
};
static int
@@ -904,12 +907,15 @@ static struct grecs_keyword notify_event_kw[] = {
{ "recipient", N_("who"), N_("Notify this recipient"),
grecs_type_string, NULL, offsetof(struct notification, tgt),
cb_recipient },
{ "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 }
};
static int
cb_notify_event (enum grecs_callback_command cmd,
grecs_locus_t *locus,
@@ -1453,12 +1459,15 @@ static struct grecs_keyword wydawca_kw[] = {
{ "spool", N_("tag: string"), N_("Define distribution spool"),
grecs_type_section, NULL, 0,
cb_spool, NULL, spool_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 }
};
void
config_help ()
diff --git a/src/gpg.c b/src/gpg.c
index 71be53c..1389845 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -125,14 +125,14 @@ remove_homedir ()
logmsg (LOG_DEBUG, _("removing GNUPG home directory: %s"), homedir);
if (rmdir_r (homedir))
logmsg (LOG_CRIT, _("failed to remove GPG directory %s"), homedir);
}
/* Create a temporary GPG home directory */
-int
-wydawca_gpg_homedir ()
+static int
+create_gpg_homedir ()
{
if (homedir)
return 0;
homedir = xstrdup ("/tmp/wydawca-XXXXXX");
if (!mkdtemp (homedir))
@@ -219,18 +219,17 @@ gpg_verify_signature (gpgme_ctx_t ctx, gpgme_signature_t sig,
int
verify_directive_signature (struct file_triplet *trp,
const struct spool *spool)
{
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)
{
gpgme_import_result_t res;
gpgme_import_status_t pstat;
@@ -298,13 +297,13 @@ verify_detached_signature (struct file_triplet *trp,
logmsg (LOG_CRIT,
_("cannot find path to gpg binary (attempting to verify "
"the detached signature for %s"), trp->name);
return 1;
}
- wydawca_gpg_homedir ();
+ create_gpg_homedir ();
argv[0] = info->file_name;
argv[1] = "--verify";
argv[2] = trp->file[file_signature].name;
argv[3] = trp->file[file_dist].name;
argv[4] = NULL;
diff --git a/src/mail.c b/src/mail.c
index 91ea502..15c2937 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -14,22 +14,24 @@
You should have received a copy of the GNU General Public License along
with wydawca. If not, see <http://www.gnu.org/licenses/>. */
#include "wydawca.h"
#include <mail.h>
#include <hash.h>
+#include <gpgme.h>
int mailer_opened;
mu_mailer_t mailer;
mu_address_t admin_address;
mu_address_t from_address;
unsigned long mail_admin_mask;
unsigned long owner_notification_flags;
char *user_message_template[MAX_EVENT];
char *admin_stat_message;
+char *admin_stat_sign_key;
void
mail_init ()
{
if (!mailer)
{
@@ -41,14 +43,209 @@ mail_init ()
logmsg (LOG_ERR, _("cannot create default mailer `%s': %s"),
url, mu_strerror (rc));
}
}
}
+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;
mu_stream_t stream = NULL;
mu_header_t hdr;
int mailer_flags = 0;
@@ -88,13 +285,13 @@ mail_send_message (mu_address_t rcpt, const char *text)
mu_debug_t debug;
mu_mailer_get_debug (mailer, &debug);
mu_debug_set_level (debug, MU_DEBUG_TRACE | MU_DEBUG_PROT);
if (debug_level > 2)
mailer_flags = MAILER_FLAG_DEBUG_DATA;
}
-
+
if (!mailer_opened)
{
if ((rc = mu_mailer_open (mailer, mailer_flags)))
{
mu_url_t url = NULL;
mu_mailer_get_url (mailer, &url);
@@ -103,16 +300,22 @@ mail_send_message (mu_address_t rcpt, const char *text)
mu_strerror (rc));
return;
}
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));
}
void
mail_finish ()
{
@@ -241,15 +444,12 @@ mail_stats ()
buf = xmalloc (size + 1);
mu_address_to_string (admin_address, buf, size + 1, NULL);
logmsg (LOG_DEBUG, _("sending stats to %s"), buf);
free (buf);
}
- if (dry_run_mode)
- return;
-
tc = timer_get_count () * 3;
exp = make_stat_expansion (tc + 1);
time (&t);
exp[0].kw = "date";
exp[0].value = exp[0].storage = xstrdup (ctime (&t));
exp[0].value [strlen (exp[0].value) - 1] = 0;
@@ -261,13 +461,13 @@ mail_stats ()
logmsg (LOG_ERR, _("undefined message reference: %s"),
admin_stat_message);
return;
}
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);
timer_free_meta (exp + 1, tc);
free (exp);
}
@@ -363,12 +563,14 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
void
do_notify (struct file_triplet *trp, enum notification_event ev,
struct notification *ntf)
{
mu_address_t rcpt = NULL;
const char *errp;
+ const char *msg;
+
switch (ntf->tgt)
{
case notify_read:
rcpt = NULL;
break;
@@ -405,27 +607,25 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
mu_address_to_string (rcpt, buf, size + 1, NULL);
logmsg (LOG_DEBUG, _("notifying %s (project %s) about %s"),
buf, trp->project, notification_event_str (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);
}
void
diff --git a/src/wydawca.c b/src/wydawca.c
index 07cac5c..f098bb1 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -42,12 +42,13 @@ int single_process_option = -1;
int daemon_mode = 0;
int foreground;
int single_process;
time_t wakeup_interval;
gl_list_t all_spool_aliases;
+char *wydawca_gpg_homedir;
struct grecs_sockaddr listen_sockaddr;
unsigned wydawca_stat[MAX_STAT];
void
diff --git a/src/wydawca.h b/src/wydawca.h
index 805b72b..96fd336 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -278,12 +278,13 @@ enum notification_target
struct notification
{
struct notification *next;
enum notification_event ev;
enum notification_target tgt;
+ const char *sign_keys;
const char *msg;
};
void register_message_template (const char *name, const char *text);
void notify (struct notification *,
@@ -324,12 +325,13 @@ extern time_t file_sweep_time; /* Unlink stale file after this amount of time
extern char *tar_command_name; /* Name of the tar command */
extern unsigned wydawca_stat[MAX_STAT];
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;
extern char *lockdir;
extern time_t lock_expire_time;
@@ -341,12 +343,14 @@ extern time_t wakeup_interval;
extern int foreground;
extern int single_process;
extern struct grecs_sockaddr listen_sockaddr;
extern gl_list_t all_spool_aliases;
+extern char *wydawca_gpg_homedir;
+
#define UPDATE_STATS(what) \
do \
{ \
if (what >= MAX_STAT) abort(); \
wydawca_stat[what]++; \
} \

Return to:

Send suggestions and report system problems to the System administrator.