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/mail.c | |
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/mail.c')
-rw-r--r-- | src/mail.c | 244 |
1 files changed, 222 insertions, 22 deletions
@@ -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 | ||
21 | int mailer_opened; | 22 | int mailer_opened; |
22 | mu_mailer_t mailer; | 23 | mu_mailer_t mailer; |
@@ -27,6 +28,7 @@ unsigned long owner_notification_flags; | |||
27 | char *user_message_template[MAX_EVENT]; | 28 | char *user_message_template[MAX_EVENT]; |
28 | 29 | ||
29 | char *admin_stat_message; | 30 | char *admin_stat_message; |
31 | char *admin_stat_sign_key; | ||
30 | 32 | ||
31 | void | 33 | void |
32 | mail_init () | 34 | mail_init () |
@@ -44,8 +46,203 @@ mail_init () | |||
44 | } | 46 | } |
45 | } | 47 | } |
46 | 48 | ||
49 | struct mu_stream_handle | ||
50 | { | ||
51 | mu_stream_t str; | ||
52 | mu_off_t off; | ||
53 | }; | ||
54 | |||
55 | static ssize_t | ||
56 | mu_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 | |||
74 | static int | ||
75 | gpg_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 | |||
136 | static int | ||
137 | sign_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 | |||
47 | void | 243 | void |
48 | mail_send_message (mu_address_t rcpt, const char *text) | 244 | mail_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 |