NeoMutt  2025-12-11-949-g4870ee
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
pgp.c File Reference

PGP sign, encrypt, check routines. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "attach/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "hooks/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "cryptglue.h"
#include "globals.h"
#include "module_data.h"
#include "pgpinvoke.h"
#include "pgpkey.h"
#include "pgpmicalg.h"
#include "pgp.h"
#include "pgplib.h"
+ Include dependency graph for pgp.c:

Go to the source code of this file.

Functions

void pgp_class_void_passphrase (void)
 Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
 
bool pgp_class_valid_passphrase (void)
 Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
 
bool pgp_use_gpg_agent (void)
 Does the user want to use the gpg agent?
 
static struct PgpKeyInfokey_parent (struct PgpKeyInfo *k)
 Find a key's parent (if it's a subkey)
 
char * pgp_long_keyid (struct PgpKeyInfo *k)
 Get a key's long id.
 
char * pgp_short_keyid (struct PgpKeyInfo *k)
 Get a key's short id.
 
char * pgp_this_keyid (struct PgpKeyInfo *k)
 Get the ID of this key.
 
char * pgp_keyid (struct PgpKeyInfo *k)
 Get the ID of the main (parent) key.
 
static char * pgp_fingerprint (struct PgpKeyInfo *k)
 Get the key's fingerprint.
 
char * pgp_fpr_or_lkeyid (struct PgpKeyInfo *k)
 Get the fingerprint or long keyid.
 
static int pgp_copy_checksig (FILE *fp_in, FILE *fp_out)
 Copy PGP output and look for signs of a good signature.
 
static int pgp_check_pgp_decryption_okay_regex (FILE *fp_in)
 Check PGP output to look for successful outcome.
 
static int pgp_check_decryption_okay (FILE *fp_in)
 Check GPG output for status codes.
 
static void pgp_copy_clearsigned (FILE *fp_in, struct State *state, char *charset)
 Copy a clearsigned message, stripping the signature.
 
int pgp_class_application_handler (struct Body *b, struct State *state)
 Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.
 
static bool pgp_check_traditional_one_body (FILE *fp, struct Body *b)
 Check the body of an inline PGP message.
 
bool pgp_class_check_traditional (FILE *fp, struct Body *b, bool just_one)
 Look for inline (non-MIME) PGP content - Implements CryptModuleSpecs::pgp_check_traditional() -.
 
int pgp_class_verify_one (struct Body *b, struct State *state, const char *tempfile)
 Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
 
static void pgp_extract_keys_from_attachment (FILE *fp, struct Body *b)
 Extract pgp keys from messages/attachments.
 
void pgp_class_extract_key_from_attachment (FILE *fp, struct Body *b)
 Extract PGP key from an attachment - Implements CryptModuleSpecs::pgp_extract_key_from_attachment() -.
 
static struct Bodypgp_decrypt_part (struct Body *a, struct State *state, FILE *fp_out, struct Body *p)
 Decrypt part of a PGP message.
 
int pgp_class_decrypt_mime (FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
 Decrypt an encrypted MIME part - Implements CryptModuleSpecs::decrypt_mime() -.
 
int pgp_class_encrypted_handler (struct Body *b, struct State *state)
 Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
 
struct Bodypgp_class_sign_message (struct Body *b, const struct AddressList *from)
 Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
 
char * pgp_class_find_keys (const struct AddressList *addrlist, bool oppenc_mode)
 Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
 
struct Bodypgp_class_encrypt_message (struct Body *b, char *keylist, bool sign, const struct AddressList *from)
 PGP encrypt an email - Implements CryptModuleSpecs::pgp_encrypt_message() -.
 
struct Bodypgp_class_traditional_encryptsign (struct Body *b, SecurityFlags flags, char *keylist)
 Create an inline PGP encrypted, signed email - Implements CryptModuleSpecs::pgp_traditional_encryptsign() -.
 
SecurityFlags pgp_class_send_menu (struct Email *e)
 Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
 

Detailed Description

PGP sign, encrypt, check routines.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Alejandro Colomar

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file pgp.c.

Function Documentation

◆ pgp_use_gpg_agent()

bool pgp_use_gpg_agent ( void )

Does the user want to use the gpg agent?

Return values
trueThe user wants to use the gpg agent
Note
This functions sets the environment variable $GPG_TTY

Definition at line 124 of file pgp.c.

125{
126 char *tty = NULL;
127
128 /* GnuPG 2.1 no longer exports GPG_AGENT_INFO */
129 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
130 if (!c_pgp_use_gpg_agent)
131 return false;
132
133 tty = ttyname(0);
134 if (tty)
135 {
136 setenv("GPG_TTY", tty, 0);
137 envlist_set(&NeoMutt->env, "GPG_TTY", tty, false);
138 }
139
140 return true;
141}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
bool envlist_set(char ***envp, const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition envlist.c:88
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ key_parent()

static struct PgpKeyInfo * key_parent ( struct PgpKeyInfo * k)
static

Find a key's parent (if it's a subkey)

Parameters
kPGP key
Return values
ptrParent key

Definition at line 148 of file pgp.c.

149{
150 const bool c_pgp_ignore_subkeys = cs_subset_bool(NeoMutt->sub, "pgp_ignore_subkeys");
151 if ((k->flags & KEYFLAG_SUBKEY) && k->parent && c_pgp_ignore_subkeys)
152 k = k->parent;
153
154 return k;
155}
@ KEYFLAG_SUBKEY
Key is a subkey.
Definition lib.h:154
KeyFlags flags
Key flags.
Definition pgplib.h:53
struct PgpKeyInfo * parent
Parent key.
Definition pgplib.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_long_keyid()

char * pgp_long_keyid ( struct PgpKeyInfo * k)

Get a key's long id.

Parameters
kPGP key
Return values
ptrLong key id string

Definition at line 162 of file pgp.c.

163{
164 k = key_parent(k);
165
166 return k->keyid;
167}
static struct PgpKeyInfo * key_parent(struct PgpKeyInfo *k)
Find a key's parent (if it's a subkey)
Definition pgp.c:148
char * keyid
Key ID.
Definition pgplib.h:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_short_keyid()

char * pgp_short_keyid ( struct PgpKeyInfo * k)

Get a key's short id.

Parameters
kPGP key
Return values
ptrShort key id string

Definition at line 174 of file pgp.c.

175{
176 k = key_parent(k);
177
178 return k->keyid + 8;
179}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_this_keyid()

char * pgp_this_keyid ( struct PgpKeyInfo * k)

Get the ID of this key.

Parameters
kPGP key
Return values
ptrLong/Short key id string
Note
The string returned depends on $pgp_long_ids

Definition at line 188 of file pgp.c.

189{
190 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
191 if (c_pgp_long_ids)
192 return k->keyid;
193 return k->keyid + 8;
194}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_keyid()

char * pgp_keyid ( struct PgpKeyInfo * k)

Get the ID of the main (parent) key.

Parameters
kPGP key
Return values
ptrLong/Short key id string

Definition at line 201 of file pgp.c.

202{
203 k = key_parent(k);
204
205 return pgp_this_keyid(k);
206}
char * pgp_this_keyid(struct PgpKeyInfo *k)
Get the ID of this key.
Definition pgp.c:188
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_fingerprint()

static char * pgp_fingerprint ( struct PgpKeyInfo * k)
static

Get the key's fingerprint.

Parameters
kPGP key
Return values
ptrFingerprint string

Definition at line 213 of file pgp.c.

214{
215 k = key_parent(k);
216
217 return k->fingerprint;
218}
char * fingerprint
Key fingerprint.
Definition pgplib.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_fpr_or_lkeyid()

char * pgp_fpr_or_lkeyid ( struct PgpKeyInfo * k)

Get the fingerprint or long keyid.

Parameters
kPGP key
Return values
ptrString fingerprint or long keyid

Grab the longest key identifier available: fingerprint or else the long keyid.

The longest available should be used for internally identifying the key and for invoking pgp commands.

Definition at line 231 of file pgp.c.

232{
233 char *fingerprint = pgp_fingerprint(k);
234 return fingerprint ? fingerprint : pgp_long_keyid(k);
235}
char * pgp_long_keyid(struct PgpKeyInfo *k)
Get a key's long id.
Definition pgp.c:162
static char * pgp_fingerprint(struct PgpKeyInfo *k)
Get the key's fingerprint.
Definition pgp.c:213
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_copy_checksig()

static int pgp_copy_checksig ( FILE * fp_in,
FILE * fp_out )
static

Copy PGP output and look for signs of a good signature.

Parameters
fp_inFile to read from
fp_outFile to write to
Return values
0Success
-1Error

Definition at line 248 of file pgp.c.

249{
250 if (!fp_in || !fp_out)
251 return -1;
252
253 int rc = -1;
254
255 const struct Regex *c_pgp_good_sign = cs_subset_regex(NeoMutt->sub, "pgp_good_sign");
256 if (c_pgp_good_sign && c_pgp_good_sign->regex)
257 {
258 char *line = NULL;
259 size_t linelen;
260
261 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NONE)))
262 {
263 if (mutt_regex_match(c_pgp_good_sign, line))
264 {
265 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
266 rc = 0;
267 }
268 else
269 {
270 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
271 }
272
273 if (mutt_strn_equal(line, "[GNUPG:] ", 9))
274 continue;
275 fputs(line, fp_out);
276 fputc('\n', fp_out);
277 }
278 FREE(&line);
279 }
280 else
281 {
282 mutt_debug(LL_DEBUG2, "No pattern\n");
283 mutt_file_copy_stream(fp_in, fp_out);
284 rc = 1;
285 }
286
287 return rc;
288}
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition helpers.c:217
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:678
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition regex.c:614
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
Cached regular expression.
Definition regex3.h:85
regex_t * regex
compiled expression
Definition regex3.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_check_pgp_decryption_okay_regex()

static int pgp_check_pgp_decryption_okay_regex ( FILE * fp_in)
static

Check PGP output to look for successful outcome.

Parameters
fp_inFile to read from
Return values
0Success
-1Error

Checks PGP output messages to look for the $pgp_decryption_okay message. This protects against messages with multipart/encrypted headers but which aren't actually encrypted.

Definition at line 300 of file pgp.c.

301{
302 int rc = -1;
303
304 const struct Regex *c_pgp_decryption_okay = cs_subset_regex(NeoMutt->sub, "pgp_decryption_okay");
305 if (c_pgp_decryption_okay && c_pgp_decryption_okay->regex)
306 {
307 char *line = NULL;
308 size_t linelen;
309
310 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NONE)))
311 {
312 if (mutt_regex_match(c_pgp_decryption_okay, line))
313 {
314 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
315 rc = 0;
316 break;
317 }
318 else
319 {
320 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
321 }
322 }
323 FREE(&line);
324 }
325 else
326 {
327 mutt_debug(LL_DEBUG2, "No pattern\n");
328 rc = 1;
329 }
330
331 return rc;
332}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_check_decryption_okay()

static int pgp_check_decryption_okay ( FILE * fp_in)
static

Check GPG output for status codes.

Parameters
fp_inFile to read from
Return values
1- no patterns were matched (if delegated to decryption_okay_regex)
0- DECRYPTION_OKAY was seen, with no PLAINTEXT outside
-1- No decryption status codes were encountered
-2- PLAINTEXT was encountered outside of DECRYPTION delimiters
-3- DECRYPTION_FAILED was encountered

Checks GnuPGP status fd output for various status codes indicating an issue. If $pgp_check_gpg_decrypt_status_fd is unset, it falls back to the old behavior of just scanning for $pgp_decryption_okay.

pgp_decrypt_part() should fail if the part is not encrypted, so we return less than 0 to indicate part or all was NOT actually encrypted.

On the other hand, for pgp_application_pgp_handler(), a "BEGIN PGP MESSAGE" could indicate a signed and armored message. For that we allow -1 and -2 as "valid" (with a warning).

Definition at line 354 of file pgp.c.

355{
356 int rc = -1;
357 char *line = NULL, *s = NULL;
358 size_t linelen;
359 int inside_decrypt = 0;
360
361 const bool c_pgp_check_gpg_decrypt_status_fd = cs_subset_bool(NeoMutt->sub, "pgp_check_gpg_decrypt_status_fd");
362 if (!c_pgp_check_gpg_decrypt_status_fd)
364
365 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NONE)))
366 {
367 size_t plen = mutt_str_startswith(line, "[GNUPG:] ");
368 if (plen == 0)
369 continue;
370 s = line + plen;
371 mutt_debug(LL_DEBUG2, "checking \"%s\"\n", line);
372 if (mutt_str_startswith(s, "BEGIN_DECRYPTION"))
373 {
374 inside_decrypt = 1;
375 }
376 else if (mutt_str_startswith(s, "END_DECRYPTION"))
377 {
378 inside_decrypt = 0;
379 }
380 else if (mutt_str_startswith(s, "PLAINTEXT"))
381 {
382 if (!inside_decrypt)
383 {
384 mutt_debug(LL_DEBUG2, " PLAINTEXT encountered outside of DECRYPTION\n");
385 rc = -2;
386 break;
387 }
388 }
389 else if (mutt_str_startswith(s, "DECRYPTION_FAILED"))
390 {
391 mutt_debug(LL_DEBUG2, " DECRYPTION_FAILED encountered. Failure\n");
392 rc = -3;
393 break;
394 }
395 else if (mutt_str_startswith(s, "DECRYPTION_OKAY"))
396 {
397 /* Don't break out because we still have to check for
398 * PLAINTEXT outside of the decryption boundaries. */
399 mutt_debug(LL_DEBUG2, " DECRYPTION_OKAY encountered\n");
400 rc = 0;
401 }
402 }
403 FREE(&line);
404
405 return rc;
406}
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
static int pgp_check_pgp_decryption_okay_regex(FILE *fp_in)
Check PGP output to look for successful outcome.
Definition pgp.c:300
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_copy_clearsigned()

static void pgp_copy_clearsigned ( FILE * fp_in,
struct State * state,
char * charset )
static

Copy a clearsigned message, stripping the signature.

Parameters
fp_inFile to read from
stateState to use
charsetCharset of file

XXX charset handling: We assume that it is safe to do character set decoding first, dash decoding second here, while we do it the other way around in the main handler.

(Note that we aren't worse than Outlook &c in this, and also note that we can successfully handle anything produced by any existing versions of neomutt.)

Definition at line 421 of file pgp.c.

422{
423 char buf[8192] = { 0 };
424 bool complete, armor_header;
425
426 rewind(fp_in);
427
428 /* fromcode comes from the MIME Content-Type charset label. It might
429 * be a wrong label, so we want the ability to do corrections via
430 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
431 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_in, charset, cc_charset(), MUTT_ICONV_HOOK_FROM);
432
433 for (complete = true, armor_header = true;
434 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
435 {
436 if (!complete)
437 {
438 if (!armor_header)
439 state_puts(state, buf);
440 continue;
441 }
442
443 if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
444 break;
445
446 if (armor_header)
447 {
448 char *p = mutt_str_skip_whitespace(buf);
449 if (*p == '\0')
450 armor_header = false;
451 continue;
452 }
453
454 if (state->prefix)
455 state_puts(state, state->prefix);
456
457 if ((buf[0] == '-') && (buf[1] == ' '))
458 state_puts(state, buf + 2);
459 else
460 state_puts(state, buf);
461 }
462
464}
const char * cc_charset(void)
Get the cached value of $charset.
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition charset.c:919
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1028
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:948
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
#define state_puts(STATE, STR)
Definition state.h:64
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition string.c:556
Cursor for converting a file's encoding.
Definition charset.h:45
char * p
Current position in output buffer.
Definition charset.h:50
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_check_traditional_one_body()

static bool pgp_check_traditional_one_body ( FILE * fp,
struct Body * b )
static

Check the body of an inline PGP message.

Parameters
fpFile to read
bBody to populate
Return values
trueSuccess
falseError

Definition at line 799 of file pgp.c.

800{
801 struct Buffer *tempfile = NULL;
802 char buf[8192] = { 0 };
803 bool rc = false;
804
805 bool sgn = false;
806 bool enc = false;
807 bool key = false;
808
809 if (b->type != TYPE_TEXT)
810 goto cleanup;
811
812 tempfile = buf_pool_get();
813 buf_mktemp(tempfile);
815 {
816 unlink(buf_string(tempfile));
817 goto cleanup;
818 }
819
820 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
821 if (!fp_tmp)
822 {
823 unlink(buf_string(tempfile));
824 goto cleanup;
825 }
826
827 while (fgets(buf, sizeof(buf), fp_tmp))
828 {
829 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
830 if (plen != 0)
831 {
832 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
833 enc = true;
834 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
835 sgn = true;
836 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
837 key = true;
838 }
839 }
840 mutt_file_fclose(&fp_tmp);
841 unlink(buf_string(tempfile));
842
843 if (!enc && !sgn && !key)
844 goto cleanup;
845
846 /* fix the content type */
847
848 mutt_param_set(&b->parameter, "format", "fixed");
849 if (enc)
850 mutt_param_set(&b->parameter, "x-action", "pgp-encrypted");
851 else if (sgn)
852 mutt_param_set(&b->parameter, "x-action", "pgp-signed");
853 else if (key)
854 mutt_param_set(&b->parameter, "x-action", "pgp-keys");
855
856 rc = true;
857
858cleanup:
859 buf_pool_release(&tempfile);
860 return rc;
861}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
@ STATE_NONE
No flags are set.
Definition state.h:36
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NONE
Overwrite existing file (the default)
Definition mutt_attach.h:59
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
unsigned int type
content-type primary type, ContentType
Definition body.h:40
String manipulation buffer.
Definition buffer.h:36
#define buf_mktemp(buf)
Definition tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_extract_keys_from_attachment()

static void pgp_extract_keys_from_attachment ( FILE * fp,
struct Body * b )
static

Extract pgp keys from messages/attachments.

Parameters
fpFile to read from
bTop Attachment

Definition at line 968 of file pgp.c.

969{
970 struct State state = { 0 };
971 struct Buffer *tempfile = buf_pool_get();
972
973 buf_mktemp(tempfile);
974 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
975 if (!fp_tmp)
976 {
977 mutt_perror("%s", buf_string(tempfile));
978 goto cleanup;
979 }
980
981 state.fp_in = fp;
982 state.fp_out = fp_tmp;
983
984 mutt_body_handler(b, &state);
985
986 mutt_file_fclose(&fp_tmp);
987
990
991 mutt_file_unlink(buf_string(tempfile));
992
993cleanup:
994 buf_pool_release(&tempfile);
995}
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
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:287
#define mutt_perror(...)
Definition logging2.h:95
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1664
Keep track when processing files.
Definition state.h:54
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_decrypt_part()

static struct Body * pgp_decrypt_part ( struct Body * a,
struct State * state,
FILE * fp_out,
struct Body * p )
static

Decrypt part of a PGP message.

Parameters
aBody of attachment
stateState to use
fp_outFile to write to
pBody of parent (main email)
Return values
ptrNew Body for the attachment

Definition at line 1023 of file pgp.c.

1025{
1026 if (!a || !state || !fp_out || !p)
1027 return NULL;
1028
1030 char buf[1024] = { 0 };
1031 FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_tmp = NULL;
1032 struct Body *tattach = NULL;
1033 pid_t pid;
1034 int rv;
1035 struct Buffer *tempfile = buf_pool_get();
1036
1037 FILE *fp_pgp_err = mutt_file_mkstemp();
1038 if (!fp_pgp_err)
1039 {
1040 mutt_perror(_("Can't create temporary file"));
1041 goto cleanup;
1042 }
1043
1044 buf_mktemp(tempfile);
1045 fp_pgp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1046 if (!fp_pgp_tmp)
1047 {
1048 mutt_perror("%s", buf_string(tempfile));
1049 mutt_file_fclose(&fp_pgp_err);
1050 goto cleanup;
1051 }
1052
1053 /* Position the stream at the beginning of the body, and send the data to
1054 * the temporary file. */
1055
1056 if (!mutt_file_seek(state->fp_in, a->offset, SEEK_SET))
1057 {
1058 mutt_file_fclose(&fp_pgp_tmp);
1059 mutt_file_fclose(&fp_pgp_err);
1060 goto cleanup;
1061 }
1062 mutt_file_copy_bytes(state->fp_in, fp_pgp_tmp, a->length);
1063 mutt_file_fclose(&fp_pgp_tmp);
1064
1065 pid = pgp_invoke_decrypt(&fp_pgp_in, &fp_pgp_out, NULL, -1, -1,
1066 fileno(fp_pgp_err), buf_string(tempfile));
1067 if (pid == -1)
1068 {
1069 mutt_file_fclose(&fp_pgp_err);
1070 unlink(buf_string(tempfile));
1071 if (state->flags & STATE_DISPLAY)
1072 {
1073 state_attach_puts(state, _("[-- Error: could not create a PGP subprocess --]\n\n"));
1074 }
1075 goto cleanup;
1076 }
1077
1078 /* send the PGP passphrase to the subprocess. Never do this if the agent is
1079 * active, because this might lead to a passphrase send as the message. */
1080 if (!pgp_use_gpg_agent())
1081 fputs(mod_data->pgp_pass, fp_pgp_in);
1082 fputc('\n', fp_pgp_in);
1083 mutt_file_fclose(&fp_pgp_in);
1084
1085 /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
1086 * read_mime_header has a hard time parsing the message. */
1087 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1088 {
1089 size_t len = mutt_str_len(buf);
1090 if ((len > 1) && (buf[len - 2] == '\r'))
1091 strcpy(buf + len - 2, "\n");
1092 fputs(buf, fp_out);
1093 }
1094
1095 mutt_file_fclose(&fp_pgp_out);
1096
1097 rv = filter_wait(pid);
1098 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
1099 if (c_pgp_use_gpg_agent)
1101
1102 mutt_file_unlink(buf_string(tempfile));
1103
1104 fflush(fp_pgp_err);
1105 rewind(fp_pgp_err);
1106 if (pgp_check_decryption_okay(fp_pgp_err) < 0)
1107 {
1108 mutt_error(_("Decryption failed"));
1110 mutt_file_fclose(&fp_pgp_err);
1111 goto cleanup;
1112 }
1113
1114 if (state->flags & STATE_DISPLAY)
1115 {
1116 rewind(fp_pgp_err);
1117 if ((pgp_copy_checksig(fp_pgp_err, state->fp_out) == 0) && !rv)
1118 p->goodsig = true;
1119 else
1120 p->goodsig = false;
1121 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
1122 }
1123 mutt_file_fclose(&fp_pgp_err);
1124
1125 fflush(fp_out);
1126 rewind(fp_out);
1127
1128 if (fgetc(fp_out) == EOF)
1129 {
1130 mutt_error(_("Decryption failed"));
1132 goto cleanup;
1133 }
1134
1135 rewind(fp_out);
1136 const long size = mutt_file_get_size_fp(fp_out);
1137 if (size == 0)
1138 {
1139 goto cleanup;
1140 }
1141
1142 tattach = mutt_read_mime_header(fp_out, 0);
1143 if (tattach)
1144 {
1145 /* Need to set the length of this body part. */
1146 tattach->length = size - tattach->offset;
1147
1148 /* See if we need to recurse on this MIME part. */
1149 mutt_parse_part(fp_out, tattach);
1150 }
1151
1152cleanup:
1153 buf_pool_release(&tempfile);
1154 return tattach;
1155}
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition curs_lib.c:101
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1947
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1484
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition file.c:192
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1432
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
void pgp_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition pgp.c:71
#define mutt_error(...)
Definition logging2.h:94
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:82
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:228
#define _(a)
Definition message.h:28
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
Copy PGP output and look for signs of a good signature.
Definition pgp.c:248
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition pgp.c:124
static int pgp_check_decryption_okay(FILE *fp_in)
Check GPG output for status codes.
Definition pgp.c:354
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:181
The body of an email.
Definition body.h:36
LOFF_T offset
offset where the actual data begins
Definition body.h:52
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
bool goodsig
Good cryptographic signature.
Definition body.h:45
Ncrypt private Module data.
Definition module_data.h:39
char pgp_pass[1024]
Cached PGP Passphrase.
Definition module_data.h:51
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
#define mutt_file_mkstemp()
Definition tmp.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function: