aboutsummaryrefslogtreecommitdiff
path: root/src/mail.c
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 /src/mail.c
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 (limited to 'src/mail.c')
-rw-r--r--src/mail.c244
1 files changed, 222 insertions, 22 deletions
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 @@
17#include "wydawca.h" 17#include "wydawca.h"
18#include <mail.h> 18#include <mail.h>
19#include <hash.h> 19#include <hash.h>
20#include <gpgme.h>
20 21
21int mailer_opened; 22int mailer_opened;
22mu_mailer_t mailer; 23mu_mailer_t mailer;
@@ -27,6 +28,7 @@ unsigned long owner_notification_flags;
27char *user_message_template[MAX_EVENT]; 28char *user_message_template[MAX_EVENT];
28 29
29char *admin_stat_message; 30char *admin_stat_message;
31char *admin_stat_sign_key;
30 32
31void 33void
32mail_init () 34mail_init ()
@@ -44,8 +46,203 @@ mail_init ()
44 } 46 }
45} 47}
46 48
49struct mu_stream_handle
50{
51 mu_stream_t str;
52 mu_off_t off;
53};
54
55static ssize_t
56mu_stream_data_read_cb (void *handle, void *buffer, size_t size)
57{
58 struct mu_stream_handle *mhp = handle;
59 size_t nread;
60 int rc;
61
62 rc = mu_stream_read (mhp->str, buffer, size, mhp->off, &nread);
63 if (rc)
64 {
65 logmsg (LOG_ERR, "mu_stream_read: %s", mu_strerror (rc));
66 errno = EIO;
67 return -1;
68 }
69
70 mhp->off += nread;
71 return nread;
72}
73
74static int
75gpg_sign (gpgme_data_t *output, gpgme_data_t input, const char *sign_keys)
76{
77 gpgme_ctx_t ctx;
78 gpgme_error_t err = 0;
79 gpgme_key_t key;
80
81 err = gpgme_new (&ctx);
82 if (err)
83 {
84 logmsg (LOG_ERR, _("GPGME: cannot create context: %s"),
85 gpgme_strerror (err));
86 return 1;
87 }
88
89 err = gpgme_op_keylist_start (ctx, sign_keys, 0);
90 if (!err)
91 {
92 while ((err = gpgme_op_keylist_next (ctx, &key)) == 0)
93 {
94 err = gpgme_signers_add (ctx, key);
95 gpgme_key_release (key);
96 }
97 }
98
99 if (err && gpg_err_code (err) != GPG_ERR_EOF)
100 {
101 logmsg (LOG_ERR, _("GPGME: cannot list keys: %s"),
102 gpgme_strerror (err));
103 gpgme_release (ctx);
104 return 1;
105 }
106
107 err = gpgme_data_new (output);
108 if (err)
109 {
110 logmsg (LOG_ERR, _("%s: GPGME error: %s"),
111 "gpgme_data_new",
112 gpgme_strerror (err));
113 gpgme_release (ctx);
114 return 1;
115 }
116
117 /* FIXME: Passphrase */
118 gpgme_set_textmode (ctx, 1);
119 gpgme_set_armor (ctx, 1);
120
121 err = gpgme_op_sign (ctx, input, *output, GPGME_SIG_MODE_CLEAR);
122 if (err)
123 logmsg (LOG_ERR, _("%s: GPGME error: %s"),
124 "gpgme_op_sign",
125 gpgme_strerror (err));
126#if 0
127 /* FIXME: */
128 else if (debug_level > 1)
129 gpgme_debug_info (ctx);
130#endif
131
132 gpgme_release (ctx);
133 return err != 0;
134}
135
136static int
137sign_message (mu_message_t *pmsg, const char *key)
138{
139 mu_message_t msg = *pmsg;
140 mu_message_t newmsg;
141 mu_body_t body;
142 mu_header_t hdr;
143 struct mu_stream_handle mhn;
144 mu_stream_t istr, ostr;
145 int rc;
146 struct gpgme_data_cbs cbs;
147 gpgme_data_t input, output;
148 gpgme_error_t err;
149 char *buf = NULL;
150 size_t size = 0;
151 size_t nread;
152
153 if (debug_level)
154 logmsg (LOG_DEBUG, _("signing message as %s"), key);
155
156 if (wydawca_gpg_homedir)
157 {
158 if (debug_level > 1)
159 logmsg (LOG_DEBUG, _("setting GNUPG home directory: %s"),
160 wydawca_gpg_homedir);
161 setenv ("GNUPGHOME", wydawca_gpg_homedir, 1);
162 }
163
164 if ((rc = mu_message_get_body (msg, &body)))
165 {
166 logmsg (LOG_ERR, "mu_message_get_body: %s", mu_strerror (rc));
167 return 1;
168 }
169
170 if ((rc = mu_body_get_stream (body, &mhn.str)))
171 {
172 logmsg (LOG_ERR, "mu_message_get_stream: %s", mu_strerror (rc));
173 return 1;
174 }
175
176 mu_stream_seek (mhn.str, 0, SEEK_SET);
177 mhn.off = 0;
178
179 memset (&cbs, 0, sizeof (cbs));
180 cbs.read = mu_stream_data_read_cb;
181
182 err = gpgme_data_new_from_cbs (&input, &cbs, &mhn);
183 if (err)
184 {
185 logmsg (LOG_ERR, "gpgme_data_new_from_cbs: %s",
186 gpgme_strerror (rc));
187 return 1;
188 }
189
190 rc = gpg_sign (&output, input, key);
191
192 if (gpgme_data_seek (output, 0, SEEK_SET) == -1)
193 {
194 logmsg (LOG_ERR, "gpgme_data_seek: %s", strerror (errno));
195 return 1;
196 }
197
198 mu_message_create (&newmsg, NULL);
199 mu_message_get_stream (newmsg, &ostr);
200
201 /* Copy headers */
202 mu_message_get_header (msg, &hdr);
203 mu_header_get_stream (hdr, &istr);
204 mu_stream_seek (istr, 0, SEEK_SET);
205 while ((rc = mu_stream_sequential_getline (istr, &buf, &size, &nread)) == 0
206 && nread)
207 {
208 rc = mu_stream_sequential_write (ostr, buf, nread);
209 if (rc)
210 {
211 logmsg (LOG_ERR, "mu_stream_sequential_write: %s",
212 mu_strerror (rc));
213 break;
214 }
215 }
216
217 if (rc == 0)
218 {
219 while ((nread = gpgme_data_read (output, buf, size)) > 0)
220 {
221 rc = mu_stream_sequential_write (ostr, buf, nread);
222 if (rc)
223 {
224 logmsg (LOG_ERR, "mu_stream_sequential_write: %s",
225 mu_strerror (rc));
226 break;
227 }
228 }
229
230 if (rc == 0)
231 {
232 mu_message_destroy (&msg, mu_message_get_owner (msg));
233 *pmsg = newmsg;
234 }
235 }
236
237 gpgme_data_release (output);
238 free (buf);
239
240 return rc;
241}
242
47void 243void
48mail_send_message (mu_address_t rcpt, const char *text) 244mail_send_message (mu_address_t rcpt, const char *text,
245 const char *signer_key)
49{ 246{
50 int rc; 247 int rc;
51 mu_message_t msg; 248 mu_message_t msg;
@@ -91,7 +288,7 @@ mail_send_message (mu_address_t rcpt, const char *text)
91 if (debug_level > 2) 288 if (debug_level > 2)
92 mailer_flags = MAILER_FLAG_DEBUG_DATA; 289 mailer_flags = MAILER_FLAG_DEBUG_DATA;
93 } 290 }
94 291
95 if (!mailer_opened) 292 if (!mailer_opened)
96 { 293 {
97 if ((rc = mu_mailer_open (mailer, mailer_flags))) 294 if ((rc = mu_mailer_open (mailer, mailer_flags)))
@@ -106,10 +303,16 @@ mail_send_message (mu_address_t rcpt, const char *text)
106 mailer_opened = 1; 303 mailer_opened = 1;
107 } 304 }
108 305
109 rc = mu_mailer_send_message (mailer, msg, from_address, rcpt); 306 if (signer_key)
110 if (rc) 307 sign_message (&msg, signer_key);
111 logmsg (LOG_CRIT, _("cannot send message: %s"), mu_strerror (rc)); 308
112