NeoMutt  2024-11-14-138-ge5ca67
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 "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "cryptglue.h"
#include "globals.h"
#include "handler.h"
#include "hook.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() -.
 

Variables

static char PgpPass [1024]
 Cached PGP Passphrase.
 
static time_t PgpExptime = 0
 Unix time when PgpPass expires.
 

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

128{
129 char *tty = NULL;
130
131 /* GnuPG 2.1 no longer exports GPG_AGENT_INFO */
132 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
133 if (!c_pgp_use_gpg_agent)
134 return false;
135
136 tty = ttyname(0);
137 if (tty)
138 {
139 setenv("GPG_TTY", tty, 0);
140 envlist_set(&EnvList, "GPG_TTY", tty, false);
141 }
142
143 return true;
144}
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
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 151 of file pgp.c.

152{
153 const bool c_pgp_ignore_subkeys = cs_subset_bool(NeoMutt->sub, "pgp_ignore_subkeys");
154 if ((k->flags & KEYFLAG_SUBKEY) && k->parent && c_pgp_ignore_subkeys)
155 k = k->parent;
156
157 return k;
158}
#define KEYFLAG_SUBKEY
Key is a subkey.
Definition: lib.h:140
KeyFlags flags
Definition: pgplib.h:53
struct PgpKeyInfo * parent
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 165 of file pgp.c.

166{
167 k = key_parent(k);
168
169 return k->keyid;
170}
static struct PgpKeyInfo * key_parent(struct PgpKeyInfo *k)
Find a key's parent (if it's a subkey)
Definition: pgp.c:151
char * keyid
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 177 of file pgp.c.

178{
179 k = key_parent(k);
180
181 return k->keyid + 8;
182}
+ 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 191 of file pgp.c.

192{
193 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
194 if (c_pgp_long_ids)
195 return k->keyid;
196 return k->keyid + 8;
197}
+ 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 204 of file pgp.c.

205{
206 k = key_parent(k);
207
208 return pgp_this_keyid(k);
209}
char * pgp_this_keyid(struct PgpKeyInfo *k)
Get the ID of this key.
Definition: pgp.c:191
+ 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 216 of file pgp.c.

217{
218 k = key_parent(k);
219
220 return k->fingerprint;
221}
char * 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 234 of file pgp.c.

235{
236 char *fingerprint = pgp_fingerprint(k);
237 return fingerprint ? fingerprint : pgp_long_keyid(k);
238}
char * pgp_long_keyid(struct PgpKeyInfo *k)
Get a key's long id.
Definition: pgp.c:165
static char * pgp_fingerprint(struct PgpKeyInfo *k)
Get the key's fingerprint.
Definition: pgp.c:216
+ 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 251 of file pgp.c.

252{
253 if (!fp_in || !fp_out)
254 return -1;
255
256 int rc = -1;
257
258 const struct Regex *c_pgp_good_sign = cs_subset_regex(NeoMutt->sub, "pgp_good_sign");
259 if (c_pgp_good_sign && c_pgp_good_sign->regex)
260 {
261 char *line = NULL;
262 size_t linelen;
263
264 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
265 {
266 if (mutt_regex_match(c_pgp_good_sign, line))
267 {
268 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
269 rc = 0;
270 }
271 else
272 {
273 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
274 }
275
276 if (mutt_strn_equal(line, "[GNUPG:] ", 9))
277 continue;
278 fputs(line, fp_out);
279 fputc('\n', fp_out);
280 }
281 FREE(&line);
282 }
283 else
284 {
285 mutt_debug(LL_DEBUG2, "No pattern\n");
286 mutt_file_copy_stream(fp_in, fp_out);
287 rc = 1;
288 }
289
290 return rc;
291}
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:287
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:808
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:40
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
#define FREE(x)
Definition: memory.h:55
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:425
Cached regular expression.
Definition: regex3.h:86
regex_t * regex
compiled expression
Definition: regex3.h:88
+ 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 303 of file pgp.c.

304{
305 int rc = -1;
306
307 const struct Regex *c_pgp_decryption_okay = cs_subset_regex(NeoMutt->sub, "pgp_decryption_okay");
308 if (c_pgp_decryption_okay && c_pgp_decryption_okay->regex)
309 {
310 char *line = NULL;
311 size_t linelen;
312
313 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
314 {
315 if (mutt_regex_match(c_pgp_decryption_okay, line))
316 {
317 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
318 rc = 0;
319 break;
320 }
321 else
322 {
323 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
324 }
325 }
326 FREE(&line);
327 }
328 else
329 {
330 mutt_debug(LL_DEBUG2, "No pattern\n");
331 rc = 1;
332 }
333
334 return rc;
335}
+ 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 357 of file pgp.c.

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

425{
426 char buf[8192] = { 0 };
427 bool complete, armor_header;
428
429 rewind(fp_in);
430
431 /* fromcode comes from the MIME Content-Type charset label. It might
432 * be a wrong label, so we want the ability to do corrections via
433 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
434 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_in, charset, cc_charset(), MUTT_ICONV_HOOK_FROM);
435
436 for (complete = true, armor_header = true;
437 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
438 {
439 if (!complete)
440 {
441 if (!armor_header)
442 state_puts(state, buf);
443 continue;
444 }
445
446 if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
447 break;
448
449 if (armor_header)
450 {
451 char *p = mutt_str_skip_whitespace(buf);
452 if (*p == '\0')
453 armor_header = false;
454 continue;
455 }
456
457 if (state->prefix)
458 state_puts(state, state->prefix);
459
460 if ((buf[0] == '-') && (buf[1] == ' '))
461 state_puts(state, buf + 2);
462 else
463 state_puts(state, buf);
464 }
465
467}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
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:933
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:1042
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:962
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:65
#define state_puts(STATE, STR)
Definition: state.h:58
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:551
Cursor for converting a file's encoding.
Definition: charset.h:43
char * p
Definition: charset.h:48
const char * prefix
String to add to the beginning of each output line.
Definition: state.h:51
+ 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 801 of file pgp.c.

802{
803 struct Buffer *tempfile = NULL;
804 char buf[8192] = { 0 };
805 bool rc = false;
806
807 bool sgn = false;
808 bool enc = false;
809 bool key = false;
810
811 if (b->type != TYPE_TEXT)
812 goto cleanup;
813
814 tempfile = buf_pool_get();
815 buf_mktemp(tempfile);
817 MUTT_SAVE_NO_FLAGS) != 0)
818 {
819 unlink(buf_string(tempfile));
820 goto cleanup;
821 }
822
823 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
824 if (!fp_tmp)
825 {
826 unlink(buf_string(tempfile));
827 goto cleanup;
828 }
829
830 while (fgets(buf, sizeof(buf), fp_tmp))
831 {
832 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
833 if (plen != 0)
834 {
835 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
836 enc = true;
837 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
838 sgn = true;
839 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
840 key = true;
841 }
842 }
843 mutt_file_fclose(&fp_tmp);
844 unlink(buf_string(tempfile));
845
846 if (!enc && !sgn && !key)
847 goto cleanup;
848
849 /* fix the content type */
850
851 mutt_param_set(&b->parameter, "format", "fixed");
852 if (enc)
853 mutt_param_set(&b->parameter, "x-action", "pgp-encrypted");
854 else if (sgn)
855 mutt_param_set(&b->parameter, "x-action", "pgp-signed");
856 else if (key)
857 mutt_param_set(&b->parameter, "x-action", "pgp-keys");
858
859 rc = true;
860
861cleanup:
862 buf_pool_release(&tempfile);
863 return rc;
864}
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:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
#define STATE_NO_FLAGS
No flags are set.
Definition: state.h:32
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1041
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:58
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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
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 971 of file pgp.c.

972{
973 struct State state = { 0 };
974 struct Buffer *tempfname = buf_pool_get();
975
976 buf_mktemp(tempfname);
977 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfname), "w");
978 if (!fp_tmp)
979 {
980 mutt_perror("%s", buf_string(tempfname));
981 goto cleanup;
982 }
983
984 state.fp_in = fp;
985 state.fp_out = fp_tmp;
986
987 mutt_body_handler(b, &state);
988
989 mutt_file_fclose(&fp_tmp);
990
993
994 mutt_file_unlink(buf_string(tempfname));
995
996cleanup:
997 buf_pool_release(&tempfname);
998}
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:173
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:221
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:288
#define mutt_perror(...)
Definition: logging2.h:93
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1632
Keep track when processing files.
Definition: state.h:48
FILE * fp_out
File to write to.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:49
+ 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 1026 of file pgp.c.

1028{
1029 if (!a || !state || !fp_out || !p)
1030 return NULL;
1031
1032 char buf[1024] = { 0 };
1033 FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_tmp = NULL;
1034 struct Body *tattach = NULL;
1035 pid_t pid;
1036 int rv;
1037 struct Buffer *pgptmpfile = buf_pool_get();
1038
1039 FILE *fp_pgp_err = mutt_file_mkstemp();
1040 if (!fp_pgp_err)
1041 {
1042 mutt_perror(_("Can't create temporary file"));
1043 goto cleanup;
1044 }
1045
1046 buf_mktemp(pgptmpfile);
1047 fp_pgp_tmp = mutt_file_fopen(buf_string(pgptmpfile), "w");
1048 if (!fp_pgp_tmp)
1049 {
1050 mutt_perror("%s", buf_string(pgptmpfile));
1051 mutt_file_fclose(&fp_pgp_err);
1052 goto cleanup;
1053 }
1054
1055 /* Position the stream at the beginning of the body, and send the data to
1056 * the temporary file. */
1057
1058 if (!mutt_file_seek(state->fp_in, a->offset, SEEK_SET))
1059 {
1060 mutt_file_fclose(&fp_pgp_tmp);
1061 mutt_file_fclose(&fp_pgp_err);
1062 goto cleanup;
1063 }
1064 mutt_file_copy_bytes(state->fp_in, fp_pgp_tmp, a->length);
1065 mutt_file_fclose(&fp_pgp_tmp);
1066
1067 pid = pgp_invoke_decrypt(&fp_pgp_in, &fp_pgp_out, NULL, -1, -1,
1068 fileno(fp_pgp_err), buf_string(pgptmpfile));
1069 if (pid == -1)
1070 {
1071 mutt_file_fclose(&fp_pgp_err);
1072 unlink(buf_string(pgptmpfile));
1073 if (state->flags & STATE_DISPLAY)
1074 {
1075 state_attach_puts(state, _("[-- Error: could not create a PGP subprocess --]\n\n"));
1076 }
1077 goto cleanup;
1078 }
1079
1080 /* send the PGP passphrase to the subprocess. Never do this if the agent is
1081 * active, because this might lead to a passphrase send as the message. */
1082 if (!pgp_use_gpg_agent())
1083 fputs(PgpPass, fp_pgp_in);
1084 fputc('\n', fp_pgp_in);
1085 mutt_file_fclose(&fp_pgp_in);
1086
1087 /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
1088 * read_mime_header has a hard time parsing the message. */
1089 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1090 {
1091 size_t len = mutt_str_len(buf);
1092 if ((len > 1) && (buf[len - 2] == '\r'))
1093 strcpy(buf + len - 2, "\n");
1094 fputs(buf, fp_out);
1095 }
1096
1097 mutt_file_fclose(&fp_pgp_out);
1098
1099 rv = filter_wait(pid);
1100 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
1101 if (c_pgp_use_gpg_agent)
1103
1104 mutt_file_unlink(buf_string(pgptmpfile));
1105
1106 fflush(fp_pgp_err);
1107 rewind(fp_pgp_err);
1108 if (pgp_check_decryption_okay(fp_pgp_err) < 0)
1109 {
1110 mutt_error(_("Decryption failed"));
1112 mutt_file_fclose(&fp_pgp_err);
1113 goto cleanup;
1114 }
1115
1116 if (state->flags & STATE_DISPLAY)
1117 {
1118 rewind(fp_pgp_err);
1119 if ((pgp_copy_checksig(fp_pgp_err, state->fp_out) == 0) && !rv)
1120 p->goodsig = true;
1121 else
1122 p->goodsig = false;
1123 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
1124 }
1125 mutt_file_fclose(&fp_pgp_err);
1126
1127 fflush(fp_out);
1128 rewind(fp_out);
1129
1130 if (fgetc(fp_out) == EOF)
1131 {
1132 mutt_error(_("Decryption failed"));
1134 goto cleanup;
1135 }
1136
1137 rewind(fp_out);
1138 const long size = mutt_file_get_size_fp(fp_out);
1139 if (size == 0)
1140 {
1141 goto cleanup;
1142 }
1143
1144 tattach = mutt_read_mime_header(fp_out, 0);
1145 if (tattach)
1146 {
1147 /* Need to set the length of this body part. */
1148 tattach->length = size - tattach->offset;
1149
1150 /* See if we need to recurse on this MIME part. */
1151 mutt_parse_part(fp_out, tattach);
1152 }
1153
1154cleanup:
1155 buf_pool_release(&pgptmpfile);
1156 return tattach;
1157}
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:100
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1822
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1362
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:257
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1537
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
void pgp_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition: pgp.c:76
#define mutt_error(...)
Definition: logging2.h:92
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
#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
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:33
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
static char PgpPass[1024]
Cached PGP Passphrase.
Definition: pgp.c:69
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:251
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition: pgp.c:127
static int pgp_check_decryption_okay(FILE *fp_in)
Check GPG output for status codes.
Definition: pgp.c:357
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:182
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
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:52
#define mutt_file_mkstemp()
Definition: tmp.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ PgpPass

char PgpPass[1024]
static

Cached PGP Passphrase.

Definition at line 69 of file pgp.c.

◆ PgpExptime

time_t PgpExptime = 0
static

Unix time when PgpPass expires.

Definition at line 71 of file pgp.c.