NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
pgpinvoke.c
Go to the documentation of this file.
1
32#include "config.h"
33#include <fcntl.h>
34#include <stdbool.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <unistd.h>
38#include "mutt/lib.h"
39#include "address/lib.h"
40#include "config/lib.h"
41#include "core/lib.h"
42#include "gui/lib.h"
43#include "pgpinvoke.h"
44#include "lib.h"
45#include "format_flags.h"
46#include "mutt_logging.h"
47#include "muttlib.h"
48#include "pgpkey.h"
49#include "protos.h"
50#ifdef CRYPT_BACKEND_CLASSIC_PGP
51#include "pgp.h"
52#endif
53
60{
62 const char *fname;
63 const char *sig_fname;
64 const char *signas;
65 const char *ids;
66};
67
79static const char *pgp_command_format_str(char *buf, size_t buflen, size_t col, int cols,
80 char op, const char *src, const char *prec,
81 const char *if_str, const char *else_str,
82 intptr_t data, MuttFormatFlags flags)
83{
84 char fmt[128] = { 0 };
85 struct PgpCommandContext *cctx = (struct PgpCommandContext *) data;
86 bool optional = (flags & MUTT_FORMAT_OPTIONAL);
87
88 switch (op)
89 {
90 case 'a':
91 {
92 if (!optional)
93 {
94 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
95 snprintf(buf, buflen, fmt, NONULL(cctx->signas));
96 }
97 else if (!cctx->signas)
98 optional = false;
99 break;
100 }
101 case 'f':
102 {
103 if (!optional)
104 {
105 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
106 snprintf(buf, buflen, fmt, NONULL(cctx->fname));
107 }
108 else if (!cctx->fname)
109 optional = false;
110 break;
111 }
112 case 'p':
113 {
114 if (!optional)
115 {
116 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
117 snprintf(buf, buflen, fmt, cctx->need_passphrase ? "PGPPASSFD=0" : "");
118 }
119 else if (!cctx->need_passphrase || pgp_use_gpg_agent())
120 optional = false;
121 break;
122 }
123 case 'r':
124 {
125 if (!optional)
126 {
127 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
128 snprintf(buf, buflen, fmt, NONULL(cctx->ids));
129 }
130 else if (!cctx->ids)
131 optional = false;
132 break;
133 }
134 case 's':
135 {
136 if (!optional)
137 {
138 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
139 snprintf(buf, buflen, fmt, NONULL(cctx->sig_fname));
140 }
141 else if (!cctx->sig_fname)
142 optional = false;
143 break;
144 }
145 default:
146 {
147 *buf = '\0';
148 break;
149 }
150 }
151
152 if (optional)
153 {
154 mutt_expando_format(buf, buflen, col, cols, if_str, pgp_command_format_str,
156 }
157 else if (flags & MUTT_FORMAT_OPTIONAL)
158 {
159 mutt_expando_format(buf, buflen, col, cols, else_str,
161 }
162
163 /* We return the format string, unchanged */
164 return src;
165}
166
176static void mutt_pgp_command(char *buf, size_t buflen,
177 struct PgpCommandContext *cctx, const char *fmt)
178{
179 mutt_expando_format(buf, buflen, 0, buflen, NONULL(fmt), pgp_command_format_str,
180 (intptr_t) cctx, MUTT_FORMAT_NO_FLAGS);
181 mutt_debug(LL_DEBUG2, "%s\n", buf);
182}
183
203static pid_t pgp_invoke(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
204 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
205 bool need_passphrase, const char *fname,
206 const char *sig_fname, const char *ids, const char *format)
207{
208 struct PgpCommandContext cctx = { 0 };
209 char cmd[STR_COMMAND] = { 0 };
210
211 if (!format || (*format == '\0'))
212 return (pid_t) -1;
213
215 cctx.fname = fname;
216 cctx.sig_fname = sig_fname;
217 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
218 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
219 if (c_pgp_sign_as)
220 cctx.signas = c_pgp_sign_as;
221 else
222 cctx.signas = c_pgp_default_key;
223 cctx.ids = ids;
224
225 mutt_pgp_command(cmd, sizeof(cmd), &cctx, format);
226
227 return filter_create_fd(cmd, fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in,
228 fd_pgp_out, fd_pgp_err);
229}
230
231/*
232 * The exported interface.
233 *
234 * This is historic and may be removed at some point.
235 */
236
253pid_t pgp_invoke_decode(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
254 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
255 const char *fname, bool need_passphrase)
256{
257 const char *const c_pgp_decode_command = cs_subset_string(NeoMutt->sub, "pgp_decode_command");
258 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out, fd_pgp_err,
259 need_passphrase, fname, NULL, NULL, c_pgp_decode_command);
260}
261
278pid_t pgp_invoke_verify(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
279 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
280 const char *fname, const char *sig_fname)
281{
282 const char *const c_pgp_verify_command = cs_subset_string(NeoMutt->sub, "pgp_verify_command");
283 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
284 fd_pgp_err, false, fname, sig_fname, NULL, c_pgp_verify_command);
285}
286
302pid_t pgp_invoke_decrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
303 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
304{
305 const char *const c_pgp_decrypt_command = cs_subset_string(NeoMutt->sub, "pgp_decrypt_command");
306 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
307 fd_pgp_err, true, fname, NULL, NULL, c_pgp_decrypt_command);
308}
309
325pid_t pgp_invoke_sign(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
326 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
327{
328 const char *const c_pgp_sign_command = cs_subset_string(NeoMutt->sub, "pgp_sign_command");
329 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
330 fd_pgp_err, true, fname, NULL, NULL, c_pgp_sign_command);
331}
332
350pid_t pgp_invoke_encrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
351 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
352 const char *fname, const char *uids, bool sign)
353{
354 if (sign)
355 {
356 const char *const c_pgp_encrypt_sign_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_sign_command");
357 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
358 fd_pgp_err, true, fname, NULL, uids, c_pgp_encrypt_sign_command);
359 }
360 else
361 {
362 const char *const c_pgp_encrypt_only_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_only_command");
363 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
364 fd_pgp_err, false, fname, NULL, uids, c_pgp_encrypt_only_command);
365 }
366}
367
385pid_t pgp_invoke_traditional(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
386 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
387 const char *fname, const char *uids, SecurityFlags flags)
388{
389 if (flags & SEC_ENCRYPT)
390 {
391 const char *const c_pgp_encrypt_only_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_only_command");
392 const char *const c_pgp_encrypt_sign_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_sign_command");
393 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
394 fd_pgp_err, (flags & SEC_SIGN), fname, NULL, uids,
395 (flags & SEC_SIGN) ? c_pgp_encrypt_sign_command : c_pgp_encrypt_only_command);
396 }
397 else
398 {
399 const char *const c_pgp_clear_sign_command = cs_subset_string(NeoMutt->sub, "pgp_clear_sign_command");
400 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
401 fd_pgp_err, true, fname, NULL, NULL, c_pgp_clear_sign_command);
402 }
403}
404
409{
410 char cmd[STR_COMMAND] = { 0 };
411 struct PgpCommandContext cctx = { 0 };
412
413 struct Buffer *buf_fname = mutt_buffer_pool_get();
414
415 mutt_buffer_quote_filename(buf_fname, fname, true);
416 cctx.fname = mutt_buffer_string(buf_fname);
417 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
418 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
419 if (c_pgp_sign_as)
420 cctx.signas = c_pgp_sign_as;
421 else
422 cctx.signas = c_pgp_default_key;
423
424 const char *const c_pgp_import_command = cs_subset_string(NeoMutt->sub, "pgp_import_command");
425 mutt_pgp_command(cmd, sizeof(cmd), &cctx, c_pgp_import_command);
426 if (mutt_system(cmd) != 0)
427 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd);
428
429 mutt_buffer_pool_release(&buf_fname);
430}
431
436{
437 char cmd[STR_COMMAND] = { 0 };
438
439 char *personal = NULL;
440
441 struct PgpCommandContext cctx = { 0 };
442
443 const char *const c_pgp_get_keys_command = cs_subset_string(NeoMutt->sub, "pgp_get_keys_command");
444 if (!c_pgp_get_keys_command)
445 return;
446
447 struct Buffer *buf = mutt_buffer_pool_get();
448 personal = addr->personal;
449 addr->personal = NULL;
450
451 struct Buffer *tmp = mutt_buffer_pool_get();
452 mutt_addr_to_local(addr);
453 mutt_addr_write(tmp, addr, false);
456
457 addr->personal = personal;
458
459 cctx.ids = mutt_buffer_string(buf);
460
461 mutt_pgp_command(cmd, sizeof(cmd), &cctx, c_pgp_get_keys_command);
462
463 int fd_null = open("/dev/null", O_RDWR);
464
465 if (!isendwin())
466 mutt_message(_("Fetching PGP key..."));
467
468 if (mutt_system(cmd) != 0)
469 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd);
470
471 if (!isendwin())
473
474 if (fd_null >= 0)
475 close(fd_null);
476
478}
479
495pid_t pgp_invoke_export(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
496 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
497{
498 const char *const c_pgp_export_command = cs_subset_string(NeoMutt->sub, "pgp_export_command");
499 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
500 fd_pgp_err, false, NULL, NULL, uids, c_pgp_export_command);
501}
502
518pid_t pgp_invoke_verify_key(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
519 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
520{
521 const char *const c_pgp_verify_key_command = cs_subset_string(NeoMutt->sub, "pgp_verify_key_command");
522 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
523 fd_pgp_err, false, NULL, NULL, uids, c_pgp_verify_key_command);
524}
525
542pid_t pgp_invoke_list_keys(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
543 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
544 enum PgpRing keyring, struct ListHead *hints)
545{
546 struct Buffer *uids = mutt_buffer_pool_get();
547 struct Buffer *quoted = mutt_buffer_pool_get();
548
549 struct ListNode *np = NULL;
550 STAILQ_FOREACH(np, hints, entries)
551 {
552 mutt_buffer_quote_filename(quoted, (char *) np->data, true);
554 if (STAILQ_NEXT(np, entries))
555 mutt_buffer_addch(uids, ' ');
556 }
557
558 const char *const c_pgp_list_pubring_command = cs_subset_string(NeoMutt->sub, "pgp_list_pubring_command");
559 const char *const c_pgp_list_secring_command = cs_subset_string(NeoMutt->sub, "pgp_list_secring_command");
560 pid_t rc = pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
561 fd_pgp_err, 0, NULL, NULL, mutt_buffer_string(uids),
562 (keyring == PGP_SECRING) ? c_pgp_list_secring_command :
563 c_pgp_list_pubring_command);
564
567 return rc;
568}
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1024
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1316
Email Address Handling.
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:907
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
Flags to control mutt_expando_format()
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
void pgp_class_invoke_getkeys(struct Address *addr)
Implements CryptModuleSpecs::pgp_invoke_getkeys() -.
Definition: pgpinvoke.c:435
void pgp_class_invoke_import(const char *fname)
Implements CryptModuleSpecs::pgp_invoke_import() -.
Definition: pgpinvoke.c:408
static const char * pgp_command_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a PGP command string - Implements format_t -.
Definition: pgpinvoke.c:79
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:778
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
Convenience wrapper for the gui headers.
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
NeoMutt Logging.
Some miscellaneous functions.
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition: pgp.c:127
PGP sign, encrypt, check routines.
static pid_t pgp_invoke(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, bool need_passphrase, const char *fname, const char *sig_fname, const char *ids, const char *format)
Run a PGP command.
Definition: pgpinvoke.c:203
pid_t pgp_invoke_verify_key(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
Use PGP to verify a key.
Definition: pgpinvoke.c:518
pid_t pgp_invoke_encrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *uids, bool sign)
Use PGP to encrypt a file.
Definition: pgpinvoke.c:350
pid_t pgp_invoke_decode(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, bool need_passphrase)
Use PGP to decode a message.
Definition: pgpinvoke.c:253
pid_t pgp_invoke_traditional(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *uids, SecurityFlags flags)
Use PGP to create in inline-signed message.
Definition: pgpinvoke.c:385
pid_t pgp_invoke_sign(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
Use PGP to sign a file.
Definition: pgpinvoke.c:325
pid_t pgp_invoke_verify(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *sig_fname)
Use PGP to verify a message.
Definition: pgpinvoke.c:278
static void mutt_pgp_command(char *buf, size_t buflen, struct PgpCommandContext *cctx, const char *fmt)
Prepare a PGP Command.
Definition: pgpinvoke.c:176
pid_t pgp_invoke_export(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
Use PGP to export a key from the user's keyring.
Definition: pgpinvoke.c:495
pid_t pgp_invoke_list_keys(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, enum PgpRing keyring, struct ListHead *hints)
Find matching PGP Keys.
Definition: pgpinvoke.c:542
pid_t pgp_invoke_decrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
Use PGP to decrypt a file.
Definition: pgpinvoke.c:302
Wrapper around calls to external PGP program.
PGP key management routines.
PgpRing
PGP ring type.
Definition: pgpkey.h:38
@ PGP_SECRING
Secret keys.
Definition: pgpkey.h:40
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
Key value store.
#define NONULL(x)
Definition: string2.h:37
#define STR_COMMAND
Enough space for a long command line.
Definition: string2.h:35
An email address.
Definition: address.h:36
char * personal
Real name of address.
Definition: address.h:37
String manipulation buffer.
Definition: buffer.h:34
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Data for a PGP command.
Definition: pgpinvoke.c:60
bool need_passphrase
p
Definition: pgpinvoke.c:61
const char * signas
a
Definition: pgpinvoke.c:64
const char * fname
f
Definition: pgpinvoke.c:62
const char * ids
r
Definition: pgpinvoke.c:65
const char * sig_fname
s
Definition: pgpinvoke.c:63