NeoMutt  2025-12-11-1031-gfb8e54
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()

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()

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()

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()

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()

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()

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 fseek(fp_in, 0, SEEK_SET);
428 clearerr(fp_in);
429
430 /* fromcode comes from the MIME Content-Type charset label. It might
431 * be a wrong label, so we want the ability to do corrections via
432 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
433 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_in, charset, cc_charset(), MUTT_ICONV_HOOK_FROM);
434
435 for (complete = true, armor_header = true;
436 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
437 {
438 if (!complete)
439 {
440 if (!armor_header)
441 state_puts(state, buf);
442 continue;
443 }
444
445 if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
446 break;
447
448 if (armor_header)
449 {
450 char *p = mutt_str_skip_whitespace(buf);
451 if (*p == '\0')
452 armor_header = false;
453 continue;
454 }
455
456 if (state->prefix)
457 state_puts(state, state->prefix);
458
459 if ((buf[0] == '-') && (buf[1] == ' '))
460 state_puts(state, buf + 2);
461 else
462 state_puts(state, buf);
463 }
464
466}
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()

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 809 of file pgp.c.

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

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 979 of file pgp.c.

980{
981 struct State state = { 0 };
982 struct Buffer *tempfile = buf_pool_get();
983
984 buf_mktemp(tempfile);
985 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
986 if (!fp_tmp)
987 {
988 mutt_perror("%s", buf_string(tempfile));
989 goto cleanup;
990 }
991
992 state.fp_in = fp;
993 state.fp_out = fp_tmp;
994
995 mutt_body_handler(b, &state);
996
997 mutt_file_fclose(&fp_tmp);
998
1001
1002 mutt_file_unlink(buf_string(tempfile));
1003
1004cleanup:
1005 buf_pool_release(&tempfile);
1006}
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:1671
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()

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 1034 of file pgp.c.

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