NeoMutt  2025-12-11-977-g8a21d8
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 = 0;
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:618
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 = 0;
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;
358 char *s = NULL;
359 size_t linelen = 0;
360 int inside_decrypt = 0;
361
362 const bool c_pgp_check_gpg_decrypt_status_fd = cs_subset_bool(NeoMutt->sub, "pgp_check_gpg_decrypt_status_fd");
363 if (!c_pgp_check_gpg_decrypt_status_fd)
365
366 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NONE)))
367 {
368 size_t plen = mutt_str_startswith(line, "[GNUPG:] ");
369 if (plen == 0)
370 continue;
371 s = line + plen;
372 mutt_debug(LL_DEBUG2, "checking \"%s\"\n", line);
373 if (mutt_str_startswith(s, "BEGIN_DECRYPTION"))
374 {
375 inside_decrypt = 1;
376 }
377 else if (mutt_str_startswith(s, "END_DECRYPTION"))
378 {
379 inside_decrypt = 0;
380 }
381 else if (mutt_str_startswith(s, "PLAINTEXT"))
382 {
383 if (!inside_decrypt)
384 {
385 mutt_debug(LL_DEBUG2, " PLAINTEXT encountered outside of DECRYPTION\n");
386 rc = -2;
387 break;
388 }
389 }
390 else if (mutt_str_startswith(s, "DECRYPTION_FAILED"))
391 {
392 mutt_debug(LL_DEBUG2, " DECRYPTION_FAILED encountered. Failure\n");
393 rc = -3;
394 break;
395 }
396 else if (mutt_str_startswith(s, "DECRYPTION_OKAY"))
397 {
398 /* Don't break out because we still have to check for
399 * PLAINTEXT outside of the decryption boundaries. */
400 mutt_debug(LL_DEBUG2, " DECRYPTION_OKAY encountered\n");
401 rc = 0;
402 }
403 }
404 FREE(&line);
405
406 return rc;
407}
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 422 of file pgp.c.

423{
424 char buf[8192] = { 0 };
425 bool complete, armor_header;
426
427 rewind(fp_in);
428
429 /* fromcode comes from the MIME Content-Type charset label. It might
430 * be a wrong label, so we want the ability to do corrections via
431 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
432 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_in, charset, cc_charset(), MUTT_ICONV_HOOK_FROM);
433
434 for (complete = true, armor_header = true;
435 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
436 {
437 if (!complete)
438 {
439 if (!armor_header)
440 state_puts(state, buf);
441 continue;
442 }
443
444 if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
445 break;
446
447 if (armor_header)
448 {
449 char *p = mutt_str_skip_whitespace(buf);
450 if (*p == '\0')
451 armor_header = false;
452 continue;
453 }
454
455 if (state->prefix)
456 state_puts(state, state->prefix);
457
458 if ((buf[0] == '-') && (buf[1] == ' '))
459 state_puts(state, buf + 2);
460 else
461 state_puts(state, buf);
462 }
463
465}
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:921
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1030
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:950
#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:666
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition string.c:557
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 803 of file pgp.c.

804{
805 struct Buffer *tempfile = NULL;
806 char buf[8192] = { 0 };
807 bool rc = false;
808
809 bool sgn = false;
810 bool enc = false;
811 bool key = false;
812
813 if (b->type != TYPE_TEXT)
814 goto cleanup;
815
816 tempfile = buf_pool_get();
817 buf_mktemp(tempfile);
819 {
820 unlink(buf_string(tempfile));
821 goto cleanup;
822 }
823
824 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
825 if (!fp_tmp)
826 {
827 unlink(buf_string(tempfile));
828 goto cleanup;
829 }
830
831 while (fgets(buf, sizeof(buf), fp_tmp))
832 {
833 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
834 if (plen != 0)
835 {
836 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
837 enc = true;
838 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
839 sgn = true;
840 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
841 key = true;
842 }
843 }
844 mutt_file_fclose(&fp_tmp);
845 unlink(buf_string(tempfile));
846
847 if (!enc && !sgn && !key)
848 goto cleanup;
849
850 /* fix the content type */
851
852 mutt_param_set(&b->parameter, "format", "fixed");
853 if (enc)
854 mutt_param_set(&b->parameter, "x-action", "pgp-encrypted");
855 else if (sgn)
856 mutt_param_set(&b->parameter, "x-action", "pgp-signed");
857 else if (key)
858 mutt_param_set(&b->parameter, "x-action", "pgp-keys");
859
860 rc = true;
861
862cleanup:
863 buf_pool_release(&tempfile);
864 return rc;
865}
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 972 of file pgp.c.

973{
974 struct State state = { 0 };
975 struct Buffer *tempfile = buf_pool_get();
976
977 buf_mktemp(tempfile);
978 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
979 if (!fp_tmp)
980 {
981 mutt_perror("%s", buf_string(tempfile));
982 goto cleanup;
983 }
984
985 state.fp_in = fp;
986 state.fp_out = fp_tmp;
987
988 mutt_body_handler(b, &state);
989
990 mutt_file_fclose(&fp_tmp);
991
994
995 mutt_file_unlink(buf_string(tempfile));
996
997cleanup:
998 buf_pool_release(&tempfile);
999}
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:1668
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 1027 of file pgp.c.

1029{
1030 if (!a || !state || !fp_out || !p)
1031 return NULL;
1032
1034 char buf[1024] = { 0 };
1035 FILE *fp_pgp_in = NULL;
1036 FILE *fp_pgp_out = NULL;
1037 FILE *fp_pgp_tmp = NULL;
1038 struct Body *tattach = NULL;
1039 pid_t pid;
1040 int rv;
1041 struct Buffer *tempfile = buf_pool_get();
1042
1043 FILE *fp_pgp_err = mutt_file_mkstemp();
1044 if (!fp_pgp_err)
1045 {
1046 mutt_perror(_("Can't create temporary file"));
1047 goto cleanup;
1048 }
1049
1050 buf_mktemp(tempfile);
1051 fp_pgp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1052 if (!fp_pgp_tmp)
1053 {
1054 mutt_perror("%s", buf_string(tempfile));
1055 mutt_file_fclose(&fp_pgp_err);
1056 goto cleanup;
1057 }
1058
1059 /* Position the stream at the beginning of the body, and send the data to
1060 * the temporary file. */
1061
1062 if (!mutt_file_seek(state->fp_in, a->offset, SEEK_SET))
1063 {
1064 mutt_file_fclose(&fp_pgp_tmp);
1065 mutt_file_fclose(&fp_pgp_err);
1066 goto cleanup;
1067 }
1068 mutt_file_copy_bytes(state->fp_in, fp_pgp_tmp, a->length);
1069 mutt_file_fclose(&fp_pgp_tmp);
1070
1071 pid = pgp_invoke_decrypt(&fp_pgp_in, &fp_pgp_out, NULL, -1, -1,
1072 fileno(fp_pgp_err), buf_string(tempfile));
1073 if (pid == -1)
1074 {
1075 mutt_file_fclose(&fp_pgp_err);
1076 unlink(buf_string(tempfile));
1077 if (state->flags & STATE_DISPLAY)
1078 {
1079 state_attach_puts(state, _("[-- Error: could not create a PGP subprocess --]\n\n"));
1080 }
1081 goto cleanup;
1082 }
1083
1084 /* send the PGP passphrase to the subprocess. Never do this if the agent is
1085 * active, because this might lead to a passphrase send as the message. */
1086 if (!pgp_use_gpg_agent())
1087 fputs(mod_data->pgp_pass, fp_pgp_in);
1088 fputc('\n', fp_pgp_in);
1089 mutt_file_fclose(&fp_pgp_in);
1090
1091 /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
1092 * read_mime_header has a hard time parsing the message. */
1093 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1094 {
1095 size_t len = mutt_str_len(buf);
1096 if ((len > 1) && (buf[len - 2] == '\r'))
1097 strcpy(buf + len - 2, "\n");
1098 fputs(buf, fp_out);
1099 }
1100
1101 mutt_file_fclose(&fp_pgp_out);
1102
1103 rv = filter_wait(pid);
1104 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
1105 if (c_pgp_use_gpg_agent)
1107
1108 mutt_file_unlink(buf_string(tempfile));
1109
1110 fflush(fp_pgp_err);
1111 rewind(fp_pgp_err);
1112 if (pgp_check_decryption_okay(fp_pgp_err) < 0)
1113 {
1114 mutt_error(_("Decryption failed"));
1116 mutt_file_fclose(&fp_pgp_err);
1117 goto cleanup;
1118 }
1119
1120 if (state->flags & STATE_DISPLAY)
1121 {
1122 rewind(fp_pgp_err);
1123 if ((pgp_copy_checksig(fp_pgp_err, state->fp_out) == 0) && !rv)
1124 p->goodsig = true;
1125 else
1126 p->goodsig = false;
1127 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
1128 }
1129 mutt_file_fclose(&fp_pgp_err);
1130
1131 fflush(fp_out);
1132 rewind(fp_out);
1133
1134 if (fgetc(fp_out) == EOF)
1135 {
1136 mutt_error(_("Decryption failed"));
1138 goto cleanup;
1139 }
1140
1141 rewind(fp_out);
1142 const long size = mutt_file_get_size_fp(fp_out);
1143 if (size == 0)
1144 {
1145 goto cleanup;
1146 }
1147
1148 tattach = mutt_read_mime_header(fp_out, 0);
1149 if (tattach)
1150 {
1151 /* Need to set the length of this body part. */
1152 tattach->length = size - tattach->offset;
1153
1154 /* See if we need to recurse on this MIME part. */
1155 mutt_parse_part(fp_out, tattach);
1156 }
1157
1158cleanup:
1159 buf_pool_release(&tempfile);
1160 return tattach;
1161}
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:1949
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:1433
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:231
#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: