NeoMutt  2020-06-26-89-g172cd3
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 <stdio.h>
36 #include <unistd.h>
37 #include "private.h"
38 #include "mutt/lib.h"
39 #include "address/lib.h"
40 #include "gui/lib.h"
41 #include "pgpinvoke.h"
42 #include "lib.h"
43 #include "format_flags.h"
44 #include "mutt_logging.h"
45 #include "muttlib.h"
46 #include "pgpkey.h"
47 #include "protos.h"
48 #ifdef CRYPT_BACKEND_CLASSIC_PGP
49 #include "pgp.h"
50 #endif
51 
58 {
60  const char *fname;
61  const char *sig_fname;
62  const char *signas;
63  const char *ids;
64 };
65 
77 static const char *pgp_command_format_str(char *buf, size_t buflen, size_t col, int cols,
78  char op, const char *src, const char *prec,
79  const char *if_str, const char *else_str,
80  intptr_t data, MuttFormatFlags flags)
81 {
82  char fmt[128];
83  struct PgpCommandContext *cctx = (struct PgpCommandContext *) data;
84  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
85 
86  switch (op)
87  {
88  case 'a':
89  {
90  if (!optional)
91  {
92  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
93  snprintf(buf, buflen, fmt, NONULL(cctx->signas));
94  }
95  else if (!cctx->signas)
96  optional = false;
97  break;
98  }
99  case 'f':
100  {
101  if (!optional)
102  {
103  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
104  snprintf(buf, buflen, fmt, NONULL(cctx->fname));
105  }
106  else if (!cctx->fname)
107  optional = false;
108  break;
109  }
110  case 'p':
111  {
112  if (!optional)
113  {
114  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
115  snprintf(buf, buflen, fmt, cctx->need_passphrase ? "PGPPASSFD=0" : "");
116  }
117  else if (!cctx->need_passphrase || pgp_use_gpg_agent())
118  optional = false;
119  break;
120  }
121  case 'r':
122  {
123  if (!optional)
124  {
125  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
126  snprintf(buf, buflen, fmt, NONULL(cctx->ids));
127  }
128  else if (!cctx->ids)
129  optional = false;
130  break;
131  }
132  case 's':
133  {
134  if (!optional)
135  {
136  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
137  snprintf(buf, buflen, fmt, NONULL(cctx->sig_fname));
138  }
139  else if (!cctx->sig_fname)
140  optional = false;
141  break;
142  }
143  default:
144  {
145  *buf = '\0';
146  break;
147  }
148  }
149 
150  if (optional)
151  {
152  mutt_expando_format(buf, buflen, col, cols, if_str, pgp_command_format_str,
153  data, MUTT_FORMAT_NO_FLAGS);
154  }
155  else if (flags & MUTT_FORMAT_OPTIONAL)
156  {
157  mutt_expando_format(buf, buflen, col, cols, else_str,
159  }
160 
161  return src;
162 }
163 
171 static void mutt_pgp_command(char *buf, size_t buflen,
172  struct PgpCommandContext *cctx, const char *fmt)
173 {
174  mutt_expando_format(buf, buflen, 0, buflen, NONULL(fmt), pgp_command_format_str,
175  (intptr_t) cctx, MUTT_FORMAT_NO_FLAGS);
176  mutt_debug(LL_DEBUG2, "%s\n", buf);
177 }
178 
198 static pid_t pgp_invoke(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
199  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
200  bool need_passphrase, const char *fname,
201  const char *sig_fname, const char *ids, const char *format)
202 {
203  struct PgpCommandContext cctx = { 0 };
204  char cmd[STR_COMMAND];
205 
206  if (!format || (*format == '\0'))
207  return (pid_t) -1;
208 
210  cctx.fname = fname;
211  cctx.sig_fname = sig_fname;
212  if (C_PgpSignAs)
213  cctx.signas = C_PgpSignAs;
214  else
215  cctx.signas = C_PgpDefaultKey;
216  cctx.ids = ids;
217 
218  mutt_pgp_command(cmd, sizeof(cmd), &cctx, format);
219 
220  return filter_create_fd(cmd, fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in,
221  fd_pgp_out, fd_pgp_err);
222 }
223 
224 /*
225  * The exported interface.
226  *
227  * This is historic and may be removed at some point.
228  */
229 
246 pid_t pgp_invoke_decode(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
247  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
248  const char *fname, bool need_passphrase)
249 {
250  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out, fd_pgp_err,
251  need_passphrase, fname, NULL, NULL, C_PgpDecodeCommand);
252 }
253 
270 pid_t pgp_invoke_verify(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
271  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
272  const char *fname, const char *sig_fname)
273 {
274  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
275  fd_pgp_err, false, fname, sig_fname, NULL, C_PgpVerifyCommand);
276 }
277 
293 pid_t pgp_invoke_decrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
294  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
295 {
296  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
297  fd_pgp_err, true, fname, NULL, NULL, C_PgpDecryptCommand);
298 }
299 
315 pid_t pgp_invoke_sign(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
316  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
317 {
318  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
319  fd_pgp_err, true, fname, NULL, NULL, C_PgpSignCommand);
320 }
321 
339 pid_t pgp_invoke_encrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
340  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
341  const char *fname, const char *uids, bool sign)
342 {
343  if (sign)
344  {
345  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
346  fd_pgp_err, true, fname, NULL, uids, C_PgpEncryptSignCommand);
347  }
348  else
349  {
350  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
351  fd_pgp_err, false, fname, NULL, uids, C_PgpEncryptOnlyCommand);
352  }
353 }
354 
372 pid_t pgp_invoke_traditional(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
373  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
374  const char *fname, const char *uids, SecurityFlags flags)
375 {
376  if (flags & SEC_ENCRYPT)
377  {
378  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
379  fd_pgp_err, (flags & SEC_SIGN), fname, NULL, uids,
380  (flags & SEC_SIGN) ? C_PgpEncryptSignCommand : C_PgpEncryptOnlyCommand);
381  }
382  else
383  {
384  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
385  fd_pgp_err, true, fname, NULL, NULL, C_PgpClearsignCommand);
386  }
387 }
388 
393 {
394  char cmd[STR_COMMAND];
395  struct PgpCommandContext cctx = { 0 };
396 
397  struct Buffer *buf_fname = mutt_buffer_pool_get();
398 
399  mutt_buffer_quote_filename(buf_fname, fname, true);
400  cctx.fname = mutt_b2s(buf_fname);
401  if (C_PgpSignAs)
402  cctx.signas = C_PgpSignAs;
403  else
404  cctx.signas = C_PgpDefaultKey;
405 
406  mutt_pgp_command(cmd, sizeof(cmd), &cctx, C_PgpImportCommand);
407  if (mutt_system(cmd) != 0)
408  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd);
409 
410  mutt_buffer_pool_release(&buf_fname);
411 }
412 
417 {
418  char tmp[1024];
419  char cmd[STR_COMMAND];
420 
421  char *personal = NULL;
422 
423  struct PgpCommandContext cctx = { 0 };
424 
425  if (!C_PgpGetkeysCommand)
426  return;
427 
428  struct Buffer *buf = mutt_buffer_pool_get();
429  personal = addr->personal;
430  addr->personal = NULL;
431 
432  *tmp = '\0';
433  mutt_addr_to_local(addr);
434  mutt_addr_write(tmp, sizeof(tmp), addr, false);
435  mutt_buffer_quote_filename(buf, tmp, true);
436 
437  addr->personal = personal;
438 
439  cctx.ids = mutt_b2s(buf);
440 
441  mutt_pgp_command(cmd, sizeof(cmd), &cctx, C_PgpGetkeysCommand);
442 
443  int fd_null = open("/dev/null", O_RDWR);
444 
445  if (!isendwin())
446  mutt_message(_("Fetching PGP key..."));
447 
448  if (mutt_system(cmd) != 0)
449  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd);
450 
451  if (!isendwin())
453 
454  if (fd_null >= 0)
455  close(fd_null);
456 
458 }
459 
475 pid_t pgp_invoke_export(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
476  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
477 {
478  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
479  fd_pgp_err, false, NULL, NULL, uids, C_PgpExportCommand);
480 }
481 
497 pid_t pgp_invoke_verify_key(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
498  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
499 {
500  return pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in, fd_pgp_out,
501  fd_pgp_err, false, NULL, NULL, uids, C_PgpVerifyKeyCommand);
502 }
503 
520 pid_t pgp_invoke_list_keys(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err,
521  int fd_pgp_in, int fd_pgp_out, int fd_pgp_err,
522  enum PgpRing keyring, struct ListHead *hints)
523 {
524  struct Buffer *uids = mutt_buffer_pool_get();
525  struct Buffer *quoted = mutt_buffer_pool_get();
526 
527  struct ListNode *np = NULL;
528  STAILQ_FOREACH(np, hints, entries)
529  {
530  mutt_buffer_quote_filename(quoted, (char *) np->data, true);
531  mutt_buffer_addstr(uids, mutt_b2s(quoted));
532  if (STAILQ_NEXT(np, entries))
533  mutt_buffer_addch(uids, ' ');
534  }
535 
536  pid_t rc = pgp_invoke(fp_pgp_in, fp_pgp_out, fp_pgp_err, fd_pgp_in,
537  fd_pgp_out, fd_pgp_err, 0, NULL, NULL, mutt_b2s(uids),
538  (keyring == PGP_SECRING) ? C_PgpListSecringCommand :
540 
542  mutt_buffer_pool_release(&quoted);
543  return rc;
544 }
Convenience wrapper for the gui headers.
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell&#39;s quoting rules.
Definition: file.c:836
Secret keys.
Definition: pgpkey.h:38
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
PGP key management routines.
#define mutt_message(...)
Definition: logging.h:83
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
static int const char * fmt
Definition: acutest.h:488
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
const char * sig_fname
s
Definition: pgpinvoke.c:61
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
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:372
An email address.
Definition: address.h:34
char * C_PgpGetkeysCommand
Config: (pgp) External command to download a key for an email address.
Definition: config.c:82
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:78
Wrapper around calls to external PGP program.
Shared constants/structs that are private to libconn.
Flags to control mutt_expando_format()
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1342
char * C_PgpDecodeCommand
Config: (pgp) External command to decode a PGP attachment.
Definition: config.c:77
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
const char * signas
a
Definition: pgpinvoke.c:62
Email Address Handling.
Some miscellaneous functions.
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:198
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:293
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:772
char * C_PgpEncryptSignCommand
Config: (pgp) External command to encrypt and sign a message.
Definition: config.c:80
const char * fname
f
Definition: pgpinvoke.c:60
Log at debug level 2.
Definition: logging.h:41
char * C_PgpEncryptOnlyCommand
Config: (pgp) External command to encrypt, but not sign a message.
Definition: config.c:79
char * C_PgpSignAs
Config: Use this alternative key for signing messages.
Definition: config.c:52
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:270
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:246
char * C_PgpDefaultKey
Config: Default key to use for PGP operations.
Definition: config.c:51
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
bool need_passphrase
p
Definition: pgpinvoke.c:59
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
void pgp_class_invoke_import(const char *fname)
Implements CryptModuleSpecs::pgp_invoke_import()
Definition: pgpinvoke.c:392
PgpRing
PGP ring type.
Definition: pgpkey.h:35
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * C_PgpClearsignCommand
Config: (pgp) External command to inline-sign a message.
Definition: config.c:76
char * C_PgpDecryptCommand
Config: (pgp) External command to decrypt a PGP message.
Definition: config.c:78
#define mutt_b2s(buf)
Definition: buffer.h:41
Prototypes for many functions.
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:520
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:497
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition: pgp.c:117
char * C_PgpSignCommand
Config: (pgp) External command to create a detached PGP signature.
Definition: config.c:86
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:77
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
static void mutt_pgp_command(char *buf, size_t buflen, struct PgpCommandContext *cctx, const char *fmt)
Prepare a PGP Command.
Definition: pgpinvoke.c:171
char * C_PgpListPubringCommand
Config: (pgp) External command to list the public keys in a user&#39;s keyring.
Definition: config.c:84
PGP sign, encrypt, check routines.
#define STR_COMMAND
Enough space for a long command line.
Definition: string2.h:35
#define SEC_SIGN
Email is signed.
Definition: lib.h:81
char * personal
Real name of address.
Definition: address.h:36
char * data
String.
Definition: list.h:36
Log at debug level 1.
Definition: logging.h:40
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
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:339
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:315
char * C_PgpExportCommand
Config: (pgp) External command to export a public key from the user&#39;s keyring.
Definition: config.c:81
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
const char * ids
r
Definition: pgpinvoke.c:63
Data for a PGP command.
Definition: pgpinvoke.c:57
Convenience wrapper for the library headers.
A List node for strings.
Definition: list.h:34
char * C_PgpImportCommand
Config: (pgp) External command to import a key into the user&#39;s keyring.
Definition: config.c:83
char * C_PgpListSecringCommand
Config: (pgp) External command to list the private keys in a user&#39;s keyring.
Definition: config.c:85
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&#39;s keyring.
Definition: pgpinvoke.c:475
char * C_PgpVerifyKeyCommand
Config: (pgp) External command to verify key information.
Definition: config.c:88
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
char * C_PgpVerifyCommand
Config: (pgp) External command to verify PGP signatures.
Definition: config.c:87
void pgp_class_invoke_getkeys(struct Address *addr)
Implements CryptModuleSpecs::pgp_invoke_getkeys()
Definition: pgpinvoke.c:416