NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "globals.h"
47#include "mutt_logging.h"
48#include "muttlib.h"
49#include "pgpkey.h"
50#include "protos.h"
51#ifdef CRYPT_BACKEND_CLASSIC_PGP
52#include "pgp.h"
53#endif
54
66static const char *pgp_command_format_str(char *buf, size_t buflen, size_t col, int cols,
67 char op, const char *src, const char *prec,
68 const char *if_str, const char *else_str,
69 intptr_t data, MuttFormatFlags flags)
70{
71 char fmt[128] = { 0 };
72 struct PgpCommandContext *cctx = (struct PgpCommandContext *) data;
73 bool optional = (flags & MUTT_FORMAT_OPTIONAL);
74
75 switch (op)
76 {
77 case 'a':
78 {
79 if (!optional)
80 {
81 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
82 snprintf(buf, buflen, fmt, NONULL(cctx->signas));
83 }
84 else if (!cctx->signas)
85 {
86 optional = false;
87 }
88 break;
89 }
90 case 'f':
91 {
92 if (!optional)
93 {
94 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
95 snprintf(buf, buflen, fmt, NONULL(cctx->fname));
96 }
97 else if (!cctx->fname)
98 {
99 optional = false;
100 }
101 break;
102 }
103 case 'p':
104 {
105 if (!optional)
106 {
107 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
108 snprintf(buf, buflen, fmt, cctx->need_passphrase ? "PGPPASSFD=0" : "");
109 }
110 else if (!cctx->need_passphrase || pgp_use_gpg_agent())
111 {
112 optional = false;
113 }
114 break;
115 }
116 case 'r':
117 {
118 if (!optional)
119 {
120 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
121 snprintf(buf, buflen, fmt, NONULL(cctx->ids));
122 }
123 else if (!cctx->ids)
124 {
125 optional = false;
126 }
127 break;
128 }
129 case 's':
130 {
131 if (!optional)
132 {
133 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
134 snprintf(buf, buflen, fmt, NONULL(cctx->sig_fname));
135 }
136 else if (!cctx->sig_fname)
137 {
138 optional = false;
139 }
140 break;
141 }
142 default:
143 {
144 *buf = '\0';
145 break;
146 }
147 }
148
149 if (optional)
150 {
151 mutt_expando_format(buf, buflen, col, cols, if_str, pgp_command_format_str,
153 }
154 else if (flags & MUTT_FORMAT_OPTIONAL)
155 {
156 mutt_expando_format(buf, buflen, col, cols, else_str,
158 }
159
160 /* We return the format string, unchanged */
161 return src;
162}
163
173static void mutt_pgp_command(char *buf, size_t buflen,
174 struct PgpCommandContext *cctx, const char *fmt)
175{
176 mutt_expando_format(buf, buflen, 0, buflen, NONULL(fmt), pgp_command_format_str,
177 (intptr_t) cctx, MUTT_FORMAT_NO_FLAGS);
178 mutt_debug(LL_DEBUG2, "%s\n", buf);
179}
180
200static pid_t pgp_invoke(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
201 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
202 bool need_passphrase, const char *fname,
203 const char *sig_fname, const char *ids, const char *format)
204{
205 struct PgpCommandContext cctx = { 0 };
206 char cmd[STR_COMMAND] = { 0 };
207
208 if (!format || (*format == '\0'))
209 return (pid_t) -1;
210
212 cctx.fname = fname;
213 cctx.sig_fname = sig_fname;
214 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
215 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
216 if (c_pgp_sign_as)
217 cctx.signas = c_pgp_sign_as;
218 else
219 cctx.signas = c_pgp_default_key;
220 cctx.ids = ids;
221
222 mutt_pgp_command(cmd, sizeof(cmd), &cctx, format);
223
224 return filter_create_fd(cmd, fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in,
225 fd_pgp_out, fd_pgp_err, EnvList);
226}
227
228/*
229 * The exported interface.
230 *
231 * This is historic and may be removed at some point.
232 */
233
250pid_t pgp_invoke_decode(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
251 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
252 const char *fname, bool need_passphrase)
253{
254 const char *const c_pgp_decode_command = cs_subset_string(NeoMutt->sub, "pgp_decode_command");
255 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out, fd_pgp_err,
256 need_passphrase, fname, NULL, NULL, c_pgp_decode_command);
257}
258
275pid_t pgp_invoke_verify(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
276 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
277 const char *fname, const char *sig_fname)
278{
279 const char *const c_pgp_verify_command = cs_subset_string(NeoMutt->sub, "pgp_verify_command");
280 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
281 fd_pgp_err, false, fname, sig_fname, NULL, c_pgp_verify_command);
282}
283
299pid_t pgp_invoke_decrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
300 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
301{
302 const char *const c_pgp_decrypt_command = cs_subset_string(NeoMutt->sub, "pgp_decrypt_command");
303 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
304 fd_pgp_err, true, fname, NULL, NULL, c_pgp_decrypt_command);
305}
306
322pid_t pgp_invoke_sign(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
323 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
324{
325 const char *const c_pgp_sign_command = cs_subset_string(NeoMutt->sub, "pgp_sign_command");
326 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
327 fd_pgp_err, true, fname, NULL, NULL, c_pgp_sign_command);
328}
329
347pid_t pgp_invoke_encrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
348 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
349 const char *fname, const char *uids, bool sign)
350{
351 if (sign)
352 {
353 const char *const c_pgp_encrypt_sign_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_sign_command");
354 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
355 fd_pgp_err, true, fname, NULL, uids, c_pgp_encrypt_sign_command);
356 }
357 else
358 {
359 const char *const c_pgp_encrypt_only_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_only_command");
360 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
361 fd_pgp_err, false, fname, NULL, uids, c_pgp_encrypt_only_command);
362 }
363}
364
382pid_t pgp_invoke_traditional(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
383 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
384 const char *fname, const char *uids, SecurityFlags flags)
385{
386 if (flags & SEC_ENCRYPT)
387 {
388 const char *const c_pgp_encrypt_only_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_only_command");
389 const char *const c_pgp_encrypt_sign_command = cs_subset_string(NeoMutt->sub, "pgp_encrypt_sign_command");
390 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
391 fd_pgp_err, (flags & SEC_SIGN), fname, NULL, uids,
392 (flags & SEC_SIGN) ? c_pgp_encrypt_sign_command : c_pgp_encrypt_only_command);
393 }
394 else
395 {
396 const char *const c_pgp_clear_sign_command = cs_subset_string(NeoMutt->sub, "pgp_clear_sign_command");
397 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
398 fd_pgp_err, true, fname, NULL, NULL, c_pgp_clear_sign_command);
399 }
400}
401
406{
407 char cmd[STR_COMMAND] = { 0 };
408 struct PgpCommandContext cctx = { 0 };
409
410 struct Buffer *buf_fname = buf_pool_get();
411
412 buf_quote_filename(buf_fname, fname, true);
413 cctx.fname = buf_string(buf_fname);
414 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
415 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
416 if (c_pgp_sign_as)
417 cctx.signas = c_pgp_sign_as;
418 else
419 cctx.signas = c_pgp_default_key;
420
421 const char *const c_pgp_import_command = cs_subset_string(NeoMutt->sub, "pgp_import_command");
422 mutt_pgp_command(cmd, sizeof(cmd), &cctx, c_pgp_import_command);
423 if (mutt_system(cmd) != 0)
424 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd);
425
426 buf_pool_release(&buf_fname);
427}
428
433{
434 char cmd[STR_COMMAND] = { 0 };
435
436 struct Buffer *personal = NULL;
437
438 struct PgpCommandContext cctx = { 0 };
439
440 const char *const c_pgp_get_keys_command = cs_subset_string(NeoMutt->sub, "pgp_get_keys_command");
441 if (!c_pgp_get_keys_command)
442 return;
443
444 struct Buffer *buf = buf_pool_get();
445 personal = addr->personal;
446 addr->personal = NULL;
447
448 struct Buffer *tmp = buf_pool_get();
449 mutt_addr_to_local(addr);
450 mutt_addr_write(tmp, addr, false);
451 buf_quote_filename(buf, buf_string(tmp), true);
452 buf_pool_release(&tmp);
453
454 addr->personal = personal;
455
456 cctx.ids = buf_string(buf);
457
458 mutt_pgp_command(cmd, sizeof(cmd), &cctx, c_pgp_get_keys_command);
459
460 int fd_null = open("/dev/null", O_RDWR);
461
462 if (!isendwin())
463 mutt_message(_("Fetching PGP key..."));
464
465 if (mutt_system(cmd) != 0)
466 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd);
467
468 if (!isendwin())
470
471 if (fd_null >= 0)
472 close(fd_null);
473
474 buf_pool_release(&buf);
475}
476
492pid_t pgp_invoke_export(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
493 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
494{
495 const char *const c_pgp_export_command = cs_subset_string(NeoMutt->sub, "pgp_export_command");
496 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
497 fd_pgp_err, false, NULL, NULL, uids, c_pgp_export_command);
498}
499
515pid_t pgp_invoke_verify_key(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
516 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
517{
518 const char *const c_pgp_verify_key_command = cs_subset_string(NeoMutt->sub, "pgp_verify_key_command");
519 return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
520 fd_pgp_err, false, NULL, NULL, uids, c_pgp_verify_key_command);
521}
522
539pid_t pgp_invoke_list_keys(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
540 int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
541 enum PgpRing keyring, struct ListHead *hints)
542{
543 struct Buffer *uids = buf_pool_get();
544 struct Buffer *quoted = buf_pool_get();
545
546 struct ListNode *np = NULL;
547 STAILQ_FOREACH(np, hints, entries)
548 {
549 buf_quote_filename(quoted, (char *) np->data, true);
550 buf_addstr(uids, buf_string(quoted));
551 if (STAILQ_NEXT(np, entries))
552 buf_addch(uids, ' ');
553 }
554
555 const char *const c_pgp_list_pubring_command = cs_subset_string(NeoMutt->sub, "pgp_list_pubring_command");
556 const char *const c_pgp_list_secring_command = cs_subset_string(NeoMutt->sub, "pgp_list_secring_command");
557 pid_t rc = pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in,
558 fd_pgp_out, fd_pgp_err, 0, NULL, NULL, buf_string(uids),
559 (keyring == PGP_SECRING) ? c_pgp_list_secring_command :
560 c_pgp_list_pubring_command);
561
562 buf_pool_release(&uids);
563 buf_pool_release(&quoted);
564 return rc;
565}
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1047
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1341
Email Address Handling.
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void buf_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:936
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
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
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:83
void pgp_class_invoke_getkeys(struct Address *addr)
Run a command to download a PGP key - Implements CryptModuleSpecs::pgp_invoke_getkeys() -.
Definition: pgpinvoke.c:432
void pgp_class_invoke_import(const char *fname)
Import a key from a message into the user's public key ring - Implements CryptModuleSpecs::pgp_invoke...
Definition: pgpinvoke.c:405
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:66
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:739
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
Convenience wrapper for the gui headers.
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
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:77
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:79
#define SEC_SIGN
Email is signed.
Definition: lib.h:80
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition: pgp.c:128
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:200
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:515
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:347
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:250
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:382
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:322
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:275
static void mutt_pgp_command(char *buf, size_t buflen, struct PgpCommandContext *cctx, const char *fmt)
Prepare a PGP Command.
Definition: pgpinvoke.c:173
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:492
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:539
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:299
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
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
#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
struct Buffer * 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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
Data for a PGP command.
Definition: pgp.h:45
bool need_passphrase
p
Definition: pgp.h:46
const char * signas
a
Definition: pgp.h:49
const char * fname
f
Definition: pgp.h:47
const char * ids
r
Definition: pgp.h:50
const char * sig_fname
s
Definition: pgp.h:48