29 |
#ifdef HAVE_GPG |
#ifdef HAVE_GPG |
30 |
#include <gpgme.h> |
#include <gpgme.h> |
31 |
|
|
32 |
|
struct gpg_struct { |
33 |
|
char *keys; |
34 |
|
char *passphrase; |
35 |
|
}; |
36 |
|
|
37 |
|
static struct gpg_struct gpg; |
38 |
|
|
39 |
static int gpgme_init(void); |
static int gpgme_init(void); |
40 |
static char *gpg_sign(char *); |
static char *gpg_sign(char *); |
41 |
static char *gpg_encrypt_to_users(char *); |
static char *gpg_encrypt_to_users(char *); |
|
static char *gpg_encrypt_to_remailer(char *); |
|
42 |
static void gpgme_debug_info(GpgmeCtx); |
static void gpgme_debug_info(GpgmeCtx); |
43 |
|
|
44 |
#define EXTRA_GPG_BUF 4096 |
#define EXTRA_GPG_BUF 4096 |
221 |
return encrypted_data; |
return encrypted_data; |
222 |
} |
} |
223 |
|
|
|
static char * |
|
|
gpg_encrypt_to_remailer(char *gpg_data) |
|
|
{ |
|
|
GpgmeCtx ctx; |
|
|
GpgmeError err = 0; |
|
|
GpgmeData in, out; |
|
|
GpgmeRecipients rset; |
|
|
char buf[256]; |
|
|
char *data_to_encrypt; |
|
|
int size; |
|
|
size_t nread; |
|
|
|
|
|
size = strlen(gpg_data) + EXTRA_GPG_BUF; |
|
|
data_to_encrypt = (char *)xmalloc(size); |
|
|
memset(buf, 0, sizeof(buf)); |
|
|
fail_if_err(gpgme_new(&ctx)); |
|
|
gpgme_set_armor(ctx, 1); |
|
|
|
|
|
/* |
|
|
Remailer Type-I support (with GPG encryption). |
|
|
*/ |
|
|
|
|
|
if (mopt & M_RMRRT) |
|
|
sprintf(data_to_encrypt, CRLF"::"CRLF"Anon-To: %s"CRLF, rm.rrt); |
|
|
else if (mopt & M_RMPOST) |
|
|
sprintf(data_to_encrypt, CRLF"::"CRLF"Anon-Post-To: %s"CRLF, rm.post); |
|
|
if ((mopt & M_RMLT) || (mopt & M_RMRLT)) { |
|
|
char mailbuf[LINEBUFFER]; |
|
|
sprintf(mailbuf, "Latent-Time: +%s%s"CRLF, |
|
|
rm.latent_time, (mopt & M_RMRLT) ? "r" : ""); |
|
|
strcat(data_to_encrypt, mailbuf); |
|
|
} |
|
|
strcat(data_to_encrypt, CRLF); |
|
|
if (mopt & M_RMHEADER) { |
|
|
remcrlf(rm.header); |
|
|
strcat(data_to_encrypt, "##"CRLF); |
|
|
strcat(data_to_encrypt, rm.header); |
|
|
strcat(data_to_encrypt, CRLF); |
|
|
} |
|
|
strcat(data_to_encrypt, gpg_data); |
|
|
memset(buf, 0, sizeof(buf)); |
|
|
|
|
|
fail_if_err(gpgme_data_new_from_mem(&in, data_to_encrypt, |
|
|
strlen(data_to_encrypt), 0)); |
|
|
fail_if_err(gpgme_data_new(&out)); |
|
|
fail_if_err(gpgme_recipients_new(&rset)); |
|
|
fail_if_err(gpgme_recipients_add_name_with_validity(rset, gpg.rm_key, |
|
|
GPGME_VALIDITY_FULL)); |
|
|
fail_if_err(gpgme_op_encrypt(ctx, rset, in, out)); |
|
|
fail_if_err(gpgme_data_rewind(out)); |
|
|
|
|
|
if (options.termlevel == DEBUG) |
|
|
gpgme_debug_info(ctx); |
|
|
|
|
|
if (topt & T_ERROR) { |
|
|
gpgme_recipients_release(rset); |
|
|
gpgme_release(ctx); |
|
|
free(data_to_encrypt); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
memset(data_to_encrypt, 0, size); |
|
|
while (!(err = gpgme_data_read(out, buf, sizeof(buf), &nread))) |
|
|
{ |
|
|
if (size > nread) { |
|
|
strncat(data_to_encrypt, buf, nread); |
|
|
size -= nread; |
|
|
} |
|
|
else { |
|
|
size = EXTRA_GPG_BUF; |
|
|
data_to_encrypt = (char *)xrealloc((char *)data_to_encrypt, |
|
|
strlen(data_to_encrypt) + size); |
|
|
strncat(data_to_encrypt, buf, nread); |
|
|
size -= nread; |
|
|
} |
|
|
memset(buf, 0, sizeof(buf)); |
|
|
} |
|
|
if (err != GPGME_EOF) |
|
|
fail_if_err(err); |
|
|
|
|
|
gpgme_recipients_release(rset); |
|
|
gpgme_data_release(in); |
|
|
gpgme_data_release(out); |
|
|
gpgme_release(ctx); |
|
|
return data_to_encrypt; |
|
|
} |
|
224 |
|
|
225 |
void |
void |
226 |
check_gpg(void) |
gpg_proc(MESSAGE *msg, char *(*proc)(char *input)) |
227 |
{ |
{ |
228 |
#if defined(HAVE_SETENV) || defined(HAVE_PUTENV) |
char *buf; |
229 |
|
#if defined(HAVE_SETENV) || defined(HAVE_PUTENV) |
230 |
char homedir_s[MAXPATHLEN+1]; /* SUPERVISOR */ |
char homedir_s[MAXPATHLEN+1]; /* SUPERVISOR */ |
231 |
char homedir_c[MAXPATHLEN+1]; /* CLIENT */ |
char homedir_c[MAXPATHLEN+1]; /* CLIENT */ |
232 |
|
|
233 |
get_homedir(session.supervisor, homedir_s, sizeof(homedir_s)); |
get_homedir(session.supervisor, homedir_s, sizeof(homedir_s)); |
234 |
get_homedir(session.client, homedir_c, sizeof(homedir_c)); |
get_homedir(session.client, homedir_c, sizeof(homedir_c)); |
235 |
setenv("HOME", homedir_c, 1); |
setenv("HOME", homedir_c, 1); |
236 |
#endif /* HAVE_SETENV or HAVE_PUTENV */ |
#endif /* HAVE_SETENV or HAVE_PUTENV */ |
237 |
|
|
238 |
if (gpgme_init() == -1) { |
buf = proc (msg->body); |
|
if (gpg.passphrase) { |
|
|
memset(gpg.passphrase, 0, strlen(gpg.passphrase)); |
|
|
xfree(gpg.passphrase); |
|
|
} |
|
|
return; |
|
|
} |
|
239 |
|
|
240 |
if (mopt & M_GPG_SIGN) { /* Sign a message */ |
if (topt & T_ERROR) |
241 |
char *buf = gpg_sign(message.body); |
return; |
|
if (topt & T_ERROR) |
|
|
return; |
|
|
xfree(message.body); |
|
|
message.body = buf; |
|
|
} |
|
|
if (mopt & M_GPG_ENCRYPT) { /* Encrypt a message body */ |
|
|
char *buf = gpg_encrypt_to_users(message.body); |
|
|
if (topt & T_ERROR) |
|
|
return; |
|
|
xfree(message.body); |
|
|
message.body = buf; |
|
|
} |
|
|
if (mopt & M_RMGPG) { /* Remailer Type-I */ |
|
|
char *buf = gpg_encrypt_to_remailer(message.body); |
|
|
if (topt & T_ERROR) |
|
|
return; |
|
|
xfree(message.body); |
|
|
message.body = buf; |
|
|
} |
|
242 |
|
|
243 |
#if defined(HAVE_SETENV) || defined(HAVE_PUTENV) |
xfree(msg->body); |
244 |
|
msg->body = buf; |
245 |
|
|
246 |
|
#if defined(HAVE_SETENV) || defined(HAVE_PUTENV) |
247 |
setenv("HOME", homedir_s, 1); |
setenv("HOME", homedir_s, 1); |
248 |
#endif /* HAVE_SETENV or HAVE_PUTENV */ |
#endif /* HAVE_SETENV or HAVE_PUTENV */ |
249 |
|
|
|
if (gpg.passphrase) { |
|
|
memset(gpg.passphrase, 0, strlen(gpg.passphrase)); |
|
|
xfree(gpg.passphrase); |
|
|
} |
|
250 |
return; |
return; |
251 |
} |
} |
252 |
|
|
257 |
#define KW_GPG_HOME 5 |
#define KW_GPG_HOME 5 |
258 |
|
|
259 |
int |
int |
260 |
gpg_parser(int method, int key, char *arg, |
gpg_parser(int method, int key, char *arg, void *inv_data, void *func_data, |
261 |
void *inv_data, void *func_data, char *line) |
MESSAGE *msg) |
262 |
{ |
{ |
263 |
switch (key) { |
switch (key) { |
264 |
case KW_GPG_PASSPHRASE: |
case KW_GPG_PASSPHRASE: |
265 |
if (gpg.passphrase) { |
gpg.passphrase = arg; |
266 |
memset(gpg.passphrase, 0, strlen(gpg.passphrase)); |
gpgme_init(); |
267 |
xfree(gpg.passphrase); |
memset(gpg.passphrase, 0, strlen(gpg.passphrase)); |
|
} |
|
|
gpg.passphrase = allocbuf(arg, 0); |
|
|
mopt |= M_GPG_PASSPHRASE; |
|
268 |
break; |
break; |
269 |
|
|
270 |
case KW_GPG_ENCRYPT: |
case KW_GPG_ENCRYPT: |
272 |
gpg.keys = allocbuf(arg, 0); |
gpg.keys = allocbuf(arg, 0); |
273 |
gpg.keys = xrealloc(gpg.keys, strlen(gpg.keys) + 2); |
gpg.keys = xrealloc(gpg.keys, strlen(gpg.keys) + 2); |
274 |
strcat(gpg.keys, ","); |
strcat(gpg.keys, ","); |
275 |
mopt |= M_GPG_ENCRYPT; |
gpg_proc(msg, gpg_encrypt_to_users); |
276 |
break; |
break; |
277 |
|
|
278 |
case KW_GPG_SIGN: |
case KW_GPG_SIGN: |
279 |
if (strcmp(arg, "yes") |
if (strcmp(arg, "yes") == 0) |
280 |
|| !(mopt & M_GPG_PASSPHRASE)) { |
gpg_proc(msg, gpg_sign); |
|
if (gpg.passphrase) { |
|
|
memset(gpg.passphrase, 0, |
|
|
strlen(gpg.passphrase)); |
|
|
xfree(gpg.passphrase); |
|
|
} |
|
|
gpg.passphrase = allocbuf(arg, 0); |
|
|
} |
|
|
mopt |= M_GPG_SIGN; |
|
281 |
break; |
break; |
282 |
|
|
|
case KW_RM_GPG: |
|
|
xfree(gpg.rm_key); |
|
|
gpg.rm_key = allocbuf(arg, 0); |
|
|
mopt |= M_RMGPG; |
|
|
break; |
|
|
|
|
283 |
case KW_GPG_HOME: |
case KW_GPG_HOME: |
284 |
setenv("GNUPGHOME", arg, 1); |
setenv("GNUPGHOME", arg, 1); |
285 |
break; |
break; |
311 |
void |
void |
312 |
gpg_section_init() |
gpg_section_init() |
313 |
{ |
{ |
314 |
struct rc_secdef *sp = anubis_add_section("ALL"); |
struct rc_secdef *sp = anubis_add_section("RULE"); |
|
|
|
|
rc_secdef_add_child(sp, &gpg_sect_child); |
|
|
|
|
|
sp = anubis_add_section("RULE"); |
|
315 |
rc_secdef_add_child(sp, &gpg_sect_child); |
rc_secdef_add_child(sp, &gpg_sect_child); |
316 |
} |
} |
317 |
|
|