NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
smime.c File Reference

SMIME helper routines. More...

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "editor/lib.h"
#include "expando/lib.h"
#include "history/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "cryptglue.h"
#include "expando_smime.h"
#include "module_data.h"
#include "mutt_logging.h"
#include "smime.h"
+ Include dependency graph for smime.c:

Go to the source code of this file.

Functions

void smime_init (void)
 Initialise smime globals.
 
void smime_cleanup (struct NcryptModuleData *mod_data)
 Clean up smime globals.
 
static void smime_key_free (struct SmimeKey **keylist)
 Free a list of SMIME keys.
 
static struct SmimeKeysmime_copy_key (struct SmimeKey *key)
 Copy an SMIME key.
 
void smime_class_void_passphrase (void)
 Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
 
bool smime_class_valid_passphrase (void)
 Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
 
static void smime_command (struct Buffer *buf, struct SmimeCommandContext *cctx, const struct Expando *exp)
 Format an SMIME command string.
 
static pid_t smime_invoke (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *digestalg, const char *key, const char *certificates, const char *intermediates, const struct Expando *exp)
 Run an SMIME command.
 
static struct SmimeKeysmime_parse_key (char *buf)
 Parse an SMIME key block.
 
static struct SmimeKeysmime_get_candidates (const char *search, bool only_public_key)
 Find keys matching a string.
 
static struct SmimeKeysmime_get_key_by_hash (const char *hash, bool only_public_key)
 Find a key by its hash.
 
static struct SmimeKeysmime_get_key_by_addr (const char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
 Find an SIME key by address.
 
static struct SmimeKeysmime_get_key_by_str (const char *str, KeyFlags abilities, bool only_public_key)
 Find an SMIME key by string.
 
static struct SmimeKeysmime_ask_for_key (const char *prompt, KeyFlags abilities, bool only_public_key)
 Ask the user to select a key.
 
static void getkeys (const char *mailbox)
 Get the keys for a mailbox.
 
void smime_class_getkeys (struct Envelope *env)
 Get the S/MIME keys required to encrypt this email - Implements CryptModuleSpecs::smime_getkeys() -.
 
char * smime_class_find_keys (const struct AddressList *al, bool oppenc_mode)
 Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
 
static int smime_handle_cert_email (const char *certificate, const char *mailbox, bool copy, char ***buffer, int *num)
 Process an email containing certificates.
 
static char * smime_extract_certificate (const char *infile)
 Extract an SMIME certificate from a file.
 
static char * smime_extract_signer_certificate (const char *infile)
 Extract the signer's certificate.
 
void smime_class_invoke_import (const char *infile, const char *mailbox)
 Add a certificate and update index file (externally) - Implements CryptModuleSpecs::smime_invoke_import() -.
 
int smime_class_verify_sender (struct Email *e, struct Message *msg)
 Does the sender match the certificate?
 
static pid_t smime_invoke_encrypt (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *uids)
 Use SMIME to encrypt a file.
 
static pid_t smime_invoke_sign (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
 Use SMIME to sign a file.
 
struct Bodysmime_class_build_smime_entity (struct Body *b, char *certlist)
 Encrypt the email body to all recipients - Implements CryptModuleSpecs::smime_build_smime_entity() -.
 
static char * openssl_md_to_smime_micalg (const char *md)
 Change the algorithm names.
 
struct Bodysmime_class_sign_message (struct Body *b, const struct AddressList *from)
 Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
 
static pid_t smime_invoke_verify (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, int opaque)
 Use SMIME to verify a file.
 
static pid_t smime_invoke_decrypt (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
 Use SMIME to decrypt a file.
 
int smime_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 struct Bodysmime_handle_entity (struct Body *b, struct State *state, FILE *fp_out_file)
 Handle type application/pkcs7-mime.
 
int smime_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 smime_class_application_handler (struct Body *b, struct State *state)
 Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.
 
SecurityFlags smime_class_send_menu (struct Email *e)
 Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
 

Detailed Description

SMIME helper routines.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Lars Haalck
  • Anna Figueiredo Gomes
  • Alejandro Colomar
  • Tóth János

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 smime.c.

Function Documentation

◆ smime_init()

void smime_init ( void )

Initialise smime globals.

Definition at line 68 of file smime.c.

69{
71 buf_alloc(&mod_data->smime_key_to_use, 256);
72 buf_alloc(&mod_data->smime_cert_to_use, 256);
73 buf_alloc(&mod_data->smime_intermediate_to_use, 256);
74}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:80
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
Ncrypt private Module data.
Definition module_data.h:38
struct Buffer smime_cert_to_use
S/MIME certificate to use.
Definition module_data.h:58
struct Buffer smime_intermediate_to_use
S/MIME intermediate certificate to use.
Definition module_data.h:59
struct Buffer smime_key_to_use
S/MIME key to use.
Definition module_data.h:57
Container for Accounts, Notifications.
Definition neomutt.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_cleanup()

void smime_cleanup ( struct NcryptModuleData * mod_data)

Clean up smime globals.

Parameters
mod_dataNcrypt module data

Definition at line 80 of file smime.c.

81{
82 buf_dealloc(&mod_data->smime_key_to_use);
85}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition buffer.c:377
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_key_free()

static void smime_key_free ( struct SmimeKey ** keylist)
static

Free a list of SMIME keys.

Parameters
[out]keylistList of keys to free

Definition at line 91 of file smime.c.

92{
93 if (!keylist)
94 return;
95
96 struct SmimeKey *key = NULL;
97
98 while (*keylist)
99 {
100 key = *keylist;
101 *keylist = (*keylist)->next;
102
103 FREE(&key->email);
104 FREE(&key->hash);
105 FREE(&key->label);
106 FREE(&key->issuer);
107 FREE(&key);
108 }
109}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
An SIME key.
Definition smime.h:43
char * hash
Key hash.
Definition smime.h:45
struct SmimeKey * next
Linked list.
Definition smime.h:50
char * issuer
Key issuer.
Definition smime.h:47
char * email
Email address.
Definition smime.h:44
char * label
Key label.
Definition smime.h:46
+ Here is the caller graph for this function:

◆ smime_copy_key()

static struct SmimeKey * smime_copy_key ( struct SmimeKey * key)
static

Copy an SMIME key.

Parameters
keyKey to copy
Return values
ptrNewly allocated SMIME key

Definition at line 116 of file smime.c.

117{
118 if (!key)
119 return NULL;
120
121 struct SmimeKey *copy = NULL;
122
123 copy = MUTT_MEM_CALLOC(1, struct SmimeKey);
124 copy->email = mutt_str_dup(key->email);
125 copy->hash = mutt_str_dup(key->hash);
126 copy->label = mutt_str_dup(key->label);
127 copy->issuer = mutt_str_dup(key->issuer);
128 copy->trust = key->trust;
129 copy->flags = key->flags;
130
131 return copy;
132}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
KeyFlags flags
Key flags.
Definition smime.h:49
char trust
i=Invalid r=revoked e=expired u=unverified v=verified t=trusted
Definition smime.h:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_command()

static void smime_command ( struct Buffer * buf,
struct SmimeCommandContext * cctx,
const struct Expando * exp )
static

Format an SMIME command string.

Parameters
bufBuffer for the result
cctxData to pass to the formatter
expExpando to use

Definition at line 185 of file smime.c.

187{
189 mutt_debug(LL_DEBUG2, "%s\n", buf_string(buf));
190}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
int expando_render(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando + data into a string.
Definition expando.c:118
const struct ExpandoRenderCallback SmimeCommandRenderCallbacks[]
Callbacks for Smime Command Expandos.
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ MUTT_FORMAT_NONE
No flags are set.
Definition render.h:37
size_t dsize
Length of data.
Definition buffer.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke()

static pid_t smime_invoke ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname,
const char * sig_fname,
const char * cryptalg,
const char * digestalg,
const char * key,
const char * certificates,
const char * intermediates,
const struct Expando * exp )
static

Run an SMIME command.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
[in]sig_fnameSignature filename to pass to the command
[in]cryptalgEncryption algorithm
[in]digestalgHashing algorithm
[in]keySMIME key
[in]certificatesPublic certificates
[in]intermediatesIntermediate certificates
[in]expExpando format string
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 214 of file smime.c.

219{
220 struct SmimeCommandContext cctx = { 0 };
221
222 if (!exp)
223 return (pid_t) -1;
224
225 cctx.fname = fname;
226 cctx.sig_fname = sig_fname;
227 cctx.key = key;
228 cctx.cryptalg = cryptalg;
229 cctx.digestalg = digestalg;
232
233 struct Buffer *cmd = buf_pool_get();
234 smime_command(cmd, &cctx, exp);
235
236 pid_t pid = filter_create_fd(buf_string(cmd), fp_smime_in, fp_smime_out,
237 fp_smime_err, fp_smime_infd, fp_smime_outfd,
238 fp_smime_errfd, NeoMutt->env);
239 buf_pool_release(&cmd);
240 return pid;
241}
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
Run a command on a pipe (optionally connect stdin/stdout)
Definition filter.c:62
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
static void smime_command(struct Buffer *buf, struct SmimeCommandContext *cctx, const struct Expando *exp)
Format an SMIME command string.
Definition smime.c:185
String manipulation buffer.
Definition buffer.h:36
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
Data for a SIME command.
Definition smime.h:58
const char * sig_fname
s
Definition smime.h:63
const char * intermediates
i
Definition smime.h:65
const char * digestalg
d
Definition smime.h:61
const char * cryptalg
a
Definition smime.h:60
const char * key
k
Definition smime.h:59
const char * fname
f
Definition smime.h:62
const char * certificates
c
Definition smime.h:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_parse_key()

static struct SmimeKey * smime_parse_key ( char * buf)
static

Parse an SMIME key block.

Parameters
bufString to parse
Return values
ptrSMIME key
NULLError

Definition at line 249 of file smime.c.

250{
251 char *pend = NULL, *p = NULL;
252 int field = 0;
253
254 struct SmimeKey *key = MUTT_MEM_CALLOC(1, struct SmimeKey);
255
256 for (p = buf; p; p = pend)
257 {
258 /* Some users manually maintain their .index file, and use a tab
259 * as a delimiter, which the old parsing code (using fscanf)
260 * happened to allow. smime_keys uses a space, so search for both. */
261 if ((pend = strchr(p, ' ')) || (pend = strchr(p, '\t')) || (pend = strchr(p, '\n')))
262 *pend++ = 0;
263
264 /* For backward compatibility, don't count consecutive delimiters
265 * as an empty field. */
266 if (*p == '\0')
267 continue;
268
269 field++;
270
271 switch (field)
272 {
273 case 1: /* mailbox */
274 key->email = mutt_str_dup(p);
275 break;
276 case 2: /* hash */
277 key->hash = mutt_str_dup(p);
278 break;
279 case 3: /* label */
280 key->label = mutt_str_dup(p);
281 break;
282 case 4: /* issuer */
283 key->issuer = mutt_str_dup(p);
284 break;
285 case 5: /* trust */
286 key->trust = *p;
287 break;
288 case 6: /* purpose */
289 while (*p)
290 {
291 switch (*p++)
292 {
293 case 'e':
295 break;
296
297 case 's':
298 key->flags |= KEYFLAG_CANSIGN;
299 break;
300 }
301 }
302 break;
303 }
304 }
305
306 /* Old index files could be missing issuer, trust, and purpose,
307 * but anything less than that is an error. */
308 if (field < 3)
309 {
310 smime_key_free(&key);
311 return NULL;
312 }
313
314 if (field < 4)
315 key->issuer = mutt_str_dup("?");
316
317 if (field < 5)
318 key->trust = 't';
319
320 if (field < 6)
322
323 return key;
324}
@ KEYFLAG_CANSIGN
Key is suitable for signing.
Definition lib.h:147
@ KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:148
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition smime.c:91
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_get_candidates()

static struct SmimeKey * smime_get_candidates ( const char * search,
bool only_public_key )
static

Find keys matching a string.

Parameters
searchString to match
only_public_keyIf true, only get the public keys
Return values
ptrMatching key

Definition at line 332 of file smime.c.

333{
334 char buf[1024] = { 0 };
335 struct SmimeKey *key = NULL, *results = NULL;
336 struct SmimeKey **results_end = &results;
337
338 struct Buffer *index_file = buf_pool_get();
339 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
340 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
341 buf_printf(index_file, "%s/.index",
342 only_public_key ? NONULL(c_smime_certificates) : NONULL(c_smime_keys));
343
344 FILE *fp = mutt_file_fopen(buf_string(index_file), "r");
345 if (!fp)
346 {
347 mutt_perror("%s", buf_string(index_file));
348 buf_pool_release(&index_file);
349 return NULL;
350 }
351 buf_pool_release(&index_file);
352
353 while (fgets(buf, sizeof(buf), fp))
354 {
355 if (((*search == '\0')) || mutt_istr_find(buf, search))
356 {
357 key = smime_parse_key(buf);
358 if (key)
359 {
360 *results_end = key;
361 results_end = &key->next;
362 }
363 }
364 }
365
366 mutt_file_fclose(&fp);
367
368 return results;
369}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_perror(...)
Definition logging2.h:95
static int search(struct Menu *menu, int op, int *match)
Search a menu.
Definition functions.c:59
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition string.c:528
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition smime.c:249
#define NONULL(x)
Definition string2.h:44
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:

◆ smime_get_key_by_hash()

static struct SmimeKey * smime_get_key_by_hash ( const char * hash,
bool only_public_key )
static

Find a key by its hash.

Parameters
hashHash to find
only_public_keyIf true, only get the public keys
Return values
ptrMatching key

Returns the first matching key record, without prompting or checking of abilities or trust.

Definition at line 380 of file smime.c.

381{
382 struct SmimeKey *match = NULL;
383 struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
384 for (struct SmimeKey *result = results; result; result = result->next)
385 {
386 if (mutt_istr_equal(hash, result->hash))
387 {
388 match = smime_copy_key(result);
389 break;
390 }
391 }
392
393 smime_key_free(&results);
394
395 return match;
396}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition smime.c:116
static struct SmimeKey * smime_get_candidates(const char *search, bool only_public_key)
Find keys matching a string.
Definition smime.c:332
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_get_key_by_addr()

static struct SmimeKey * smime_get_key_by_addr ( const char * mailbox,
KeyFlags abilities,
bool only_public_key,
bool oppenc_mode )
static

Find an SIME key by address.

Parameters
mailboxEmail address to match
abilitiesAbilities to match, see KeyFlags
only_public_keyIf true, only get the public keys
oppenc_modeIf true, use opportunistic encryption
Return values
ptrMatching key

Definition at line 406 of file smime.c.

408{
409 if (!mailbox)
410 return NULL;
411
412 struct SmimeKey *results = NULL, *result = NULL;
413 struct SmimeKey *matches = NULL;
414 struct SmimeKey **matches_end = &matches;
415 struct SmimeKey *match = NULL;
416 struct SmimeKey *trusted_match = NULL;
417 struct SmimeKey *valid_match = NULL;
418 struct SmimeKey *return_key = NULL;
419 bool multi_trusted_matches = false;
420
421 results = smime_get_candidates(mailbox, only_public_key);
422 for (result = results; result; result = result->next)
423 {
424 if (abilities && !(result->flags & abilities))
425 {
426 continue;
427 }
428
429 if (mutt_istr_equal(mailbox, result->email))
430 {
431 match = smime_copy_key(result);
432 *matches_end = match;
433 matches_end = &match->next;
434
435 if (match->trust == 't')
436 {
437 if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
438 {
439 multi_trusted_matches = true;
440 }
441 trusted_match = match;
442 }
443 else if ((match->trust == 'u') || (match->trust == 'v'))
444 {
445 valid_match = match;
446 }
447 }
448 }
449
450 smime_key_free(&results);
451
452 if (matches)
453 {
454 if (oppenc_mode || !isatty(STDIN_FILENO))
455 {
456 const bool c_crypt_opportunistic_encrypt_strong_keys =
457 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
458 if (trusted_match)
459 return_key = smime_copy_key(trusted_match);
460 else if (valid_match && !c_crypt_opportunistic_encrypt_strong_keys)
461 return_key = smime_copy_key(valid_match);
462 else
463 return_key = NULL;
464 }
465 else if (trusted_match && !multi_trusted_matches)
466 {
467 return_key = smime_copy_key(trusted_match);
468 }
469 else
470 {
471 return_key = smime_copy_key(dlg_smime(matches, mailbox));
472 }
473
474 smime_key_free(&matches);
475 }
476
477 return return_key;
478}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
struct SmimeKey * dlg_smime(struct SmimeKey *keys, const char *query)
Get the user to select a key -.
Definition dlg_smime.c:195
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_get_key_by_str()

static struct SmimeKey * smime_get_key_by_str ( const char * str,
KeyFlags abilities,
bool only_public_key )
static

Find an SMIME key by string.

Parameters
strString to match
abilitiesAbilities to match, see KeyFlags
only_public_keyIf true, only get the public keys
Return values
ptrMatching key

Definition at line 487 of file smime.c.

488{
489 if (!str)
490 return NULL;
491
492 struct SmimeKey *results = NULL, *result = NULL;
493 struct SmimeKey *matches = NULL;
494 struct SmimeKey **matches_end = &matches;
495 struct SmimeKey *match = NULL;
496 struct SmimeKey *return_key = NULL;
497
498 results = smime_get_candidates(str, only_public_key);
499 for (result = results; result; result = result->next)
500 {
501 if (abilities && !(result->flags & abilities))
502 {
503 continue;
504 }
505
506 if (mutt_istr_equal(str, result->hash) ||
507 mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
508 {
509 match = smime_copy_key(result);
510 *matches_end = match;
511 matches_end = &match->next;
512 }
513 }
514
515 smime_key_free(&results);
516
517 if (matches)
518 {
519 return_key = smime_copy_key(dlg_smime(matches, str));
520 smime_key_free(&matches);
521 }
522
523 return return_key;
524}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_ask_for_key()

static struct SmimeKey * smime_ask_for_key ( const char * prompt,
KeyFlags abilities,
bool only_public_key )
static

Ask the user to select a key.

Parameters
promptPrompt to show the user
abilitiesAbilities to match, see KeyFlags
only_public_keyIf true, only get the public keys
Return values
ptrSelected SMIME key

Definition at line 533 of file smime.c.

534{
535 if (!prompt)
536 return NULL;
537
538 struct SmimeKey *key = NULL;
539 struct Buffer *resp = buf_pool_get();
540
542
543 while (true)
544 {
545 buf_reset(resp);
546 if (mw_get_field(prompt, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
547 {
548 goto done;
549 }
550
551 key = smime_get_key_by_str(buf_string(resp), abilities, only_public_key);
552 if (key)
553 goto done;
554
555 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
556 }
557
558done:
559 buf_pool_release(&resp);
560 return key;
561}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
#define mutt_error(...)
Definition logging2.h:94
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
#define _(a)
Definition message.h:28
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
static struct SmimeKey * smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
Find an SMIME key by string.
Definition smime.c:487
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getkeys()

static void getkeys ( const char * mailbox)
static

Get the keys for a mailbox.

Parameters
mailboxEmail address

This sets the '*ToUse' variables for an upcoming decryption, where the required key is different from $smime_default_key.

Definition at line 570 of file smime.c.

571{
573 const char *k = NULL;
574
575 struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
576
577 if (!key)
578 {
579 struct Buffer *prompt = buf_pool_get();
580 buf_printf(prompt, _("Enter keyID for %s: "), mailbox);
581 key = smime_ask_for_key(buf_string(prompt), KEYFLAG_CANENCRYPT, false);
582 buf_pool_release(&prompt);
583 }
584
585 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
586 size_t smime_keys_len = mutt_str_len(c_smime_keys);
587
588 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
589 k = key ? key->hash : NONULL(c_smime_default_key);
590
591 /* if the key is different from last time */
592 if ((buf_len(&mod_data->smime_key_to_use) <= smime_keys_len) ||
593 !mutt_istr_equal(k, mod_data->smime_key_to_use.data + smime_keys_len + 1))
594 {
596 buf_printf(&mod_data->smime_key_to_use, "%s/%s", NONULL(c_smime_keys), k);
597 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
598 buf_printf(&mod_data->smime_cert_to_use, "%s/%s", NONULL(c_smime_certificates), k);
599 }
600
601 smime_key_free(&key);
602}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
void smime_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition smime.c:137
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
static struct SmimeKey * smime_get_key_by_addr(const char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
Find an SIME key by address.
Definition smime.c:406
static struct SmimeKey * smime_ask_for_key(const char *prompt, KeyFlags abilities, bool only_public_key)
Ask the user to select a key.
Definition smime.c:533
char * data
Pointer to data.
Definition buffer.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_handle_cert_email()

static int smime_handle_cert_email ( const char * certificate,
const char * mailbox,
bool copy,
char *** buffer,
int * num )
static

Process an email containing certificates.

Parameters
[in]certificateEmail with certificates
[in]mailboxEmail address
[in]copyIf true, save the certificates to buffer
[out]bufferBuffer allocated to hold certificates
[out]numNumber of certificates in buffer
Return values
0Success
-1Error
-2Error

Definition at line 697 of file smime.c.

699{
700 char email[256] = { 0 };
701 int rc = -1, count = 0;
702 pid_t pid;
703
704 FILE *fp_err = mutt_file_mkstemp();
705 if (!fp_err)
706 {
707 mutt_perror(_("Can't create temporary file"));
708 return 1;
709 }
710
711 FILE *fp_out = mutt_file_mkstemp();
712 if (!fp_out)
713 {
714 mutt_file_fclose(&fp_err);
715 mutt_perror(_("Can't create temporary file"));
716 return 1;
717 }
718
719 const struct Expando *c_smime_get_cert_email_command =
720 cs_subset_expando(NeoMutt->sub, "smime_get_cert_email_command");
721 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
722 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_get_cert_email_command);
723 if (pid == -1)
724 {
725 mutt_message(_("Error: unable to create OpenSSL subprocess"));
726 mutt_file_fclose(&fp_err);
727 mutt_file_fclose(&fp_out);
728 return 1;
729 }
730
731 filter_wait(pid);
732
733 fflush(fp_out);
734 rewind(fp_out);
735 fflush(fp_err);
736 rewind(fp_err);
737
738 while ((fgets(email, sizeof(email), fp_out)))
739 {
740 size_t len = mutt_str_len(email);
741 if (len && (email[len - 1] == '\n'))
742 email[len - 1] = '\0';
743 if (mutt_istr_startswith(email, mailbox))
744 rc = 1;
745
746 rc = (rc < 0) ? 0 : rc;
747 count++;
748 }
749
750 if (rc == -1)
751 {
752 mutt_endwin();
753 mutt_file_copy_stream(fp_err, stdout);
754 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
755 rc = 1;
756 }
757 else if (rc == 0)
758 {
759 rc = 1;
760 }
761 else
762 {
763 rc = 0;
764 }
765
766 if (copy && buffer && num)
767 {
768 (*num) = count;
769 *buffer = MUTT_MEM_CALLOC(count, char *);
770 count = 0;
771
772 rewind(fp_out);
773 while ((fgets(email, sizeof(email), fp_out)))
774 {
775 size_t len = mutt_str_len(email);
776 if (len && (email[len - 1] == '\n'))
777 email[len - 1] = '\0';
778 (*buffer)[count] = MUTT_MEM_CALLOC(mutt_str_len(email) + 1, char);
779 strncpy((*buffer)[count], email, mutt_str_len(email));
780 count++;
781 }
782 }
783 else if (copy)
784 {
785 rc = 2;
786 }
787
788 mutt_file_fclose(&fp_out);
789 mutt_file_fclose(&fp_err);
790
791 return rc;
792}
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:175
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:153
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
#define mutt_message(...)
Definition logging2.h:93
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:228
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *digestalg, const char *key, const char *certificates, const char *intermediates, const struct Expando *exp)
Run an SMIME command.
Definition smime.c:214
Parsed Expando trees.
Definition expando.h:41
#define mutt_file_mkstemp()
Definition tmp.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_extract_certificate()

static char * smime_extract_certificate ( const char * infile)
static

Extract an SMIME certificate from a file.

Parameters
infileFile to read
Return values
ptrFilename of temporary file containing certificate

Definition at line 799 of file smime.c.

800{
801 FILE *fp_err = NULL;
802 FILE *fp_out = NULL;
803 FILE *fp_cert = NULL;
804 char *rc = NULL;
805 pid_t pid;
806 int empty;
807
808 struct Buffer *pk7out = buf_pool_get();
809 struct Buffer *certfile = buf_pool_get();
810
811 fp_err = mutt_file_mkstemp();
812 if (!fp_err)
813 {
814 mutt_perror(_("Can't create temporary file"));
815 goto cleanup;
816 }
817
818 buf_mktemp(pk7out);
819 fp_out = mutt_file_fopen(buf_string(pk7out), "w+");
820 if (!fp_out)
821 {
822 mutt_perror("%s", buf_string(pk7out));
823 goto cleanup;
824 }
825
826 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
827 * extract the full set of certificates directly. */
828 const struct Expando *c_smime_pk7out_command = cs_subset_expando(NeoMutt->sub, "smime_pk7out_command");
829 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), infile,
830 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_pk7out_command);
831 if (pid == -1)
832 {
833 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
834 goto cleanup;
835 }
836
837 filter_wait(pid);
838
839 fflush(fp_out);
840 rewind(fp_out);
841 fflush(fp_err);
842 rewind(fp_err);
843 empty = (fgetc(fp_out) == EOF);
844 if (empty)
845 {
846 mutt_perror("%s", buf_string(pk7out));
847 mutt_file_copy_stream(fp_err, stdout);
848 goto cleanup;
849 }
850 mutt_file_fclose(&fp_out);
851
852 buf_mktemp(certfile);
853 fp_cert = mutt_file_fopen(buf_string(certfile), "w+");
854 if (!fp_cert)
855 {
856 mutt_perror("%s", buf_string(certfile));
858 goto cleanup;
859 }
860
861 // Step 2: Extract the certificates from a PKCS#7 structure.
862 const struct Expando *c_smime_get_cert_command = cs_subset_expando(NeoMutt->sub, "smime_get_cert_command");
863 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_cert), fileno(fp_err),
864 buf_string(pk7out), NULL, NULL, NULL, NULL, NULL, NULL,
865 c_smime_get_cert_command);
866 if (pid == -1)
867 {
868 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
870 goto cleanup;
871 }
872
873 filter_wait(pid);
874
876
877 fflush(fp_cert);
878 rewind(fp_cert);
879 fflush(fp_err);
880 rewind(fp_err);
881 empty = (fgetc(fp_cert) == EOF);
882 if (empty)
883 {
884 mutt_file_copy_stream(fp_err, stdout);
885 goto cleanup;
886 }
887
888 mutt_file_fclose(&fp_cert);
889
890 rc = buf_strdup(certfile);
891
892cleanup:
893 mutt_file_fclose(&fp_err);
894 if (fp_out)
895 {
896 mutt_file_fclose(&fp_out);
898 }
899 if (fp_cert)
900 {
901 mutt_file_fclose(&fp_cert);
902 mutt_file_unlink(buf_string(certfile));
903 }
904 buf_pool_release(&pk7out);
905 buf_pool_release(&certfile);
906 return rc;
907}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define buf_mktemp(buf)
Definition tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_extract_signer_certificate()

static char * smime_extract_signer_certificate ( const char * infile)
static

Extract the signer's certificate.

Parameters
infileFile to read
Return values
ptrName of temporary file containing certificate

Definition at line 914 of file smime.c.

915{
916 char *cert = NULL;
917 struct Buffer *certfile = NULL;
918 pid_t pid;
919 int empty;
920
921 FILE *fp_err = mutt_file_mkstemp();
922 if (!fp_err)
923 {
924 mutt_perror(_("Can't create temporary file"));
925 return NULL;
926 }
927
928 certfile = buf_pool_get();
929 buf_mktemp(certfile);
930 FILE *fp_out = mutt_file_fopen(buf_string(certfile), "w+");
931 if (!fp_out)
932 {
933 mutt_file_fclose(&fp_err);
934 mutt_perror("%s", buf_string(certfile));
935 goto cleanup;
936 }
937
938 /* Extract signer's certificate
939 */
940 const struct Expando *c_smime_get_signer_cert_command =
941 cs_subset_expando(NeoMutt->sub, "smime_get_signer_cert_command");
942 pid = smime_invoke(NULL, NULL, NULL, -1, -1, fileno(fp_err), infile, NULL, NULL, NULL,
943 NULL, buf_string(certfile), NULL, c_smime_get_signer_cert_command);
944 if (pid == -1)
945 {
946 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
947 goto cleanup;
948 }
949
950 filter_wait(pid);
951
952 fflush(fp_out);
953 rewind(fp_out);
954 fflush(fp_err);
955 rewind(fp_err);
956 empty = (fgetc(fp_out) == EOF);
957 if (empty)
958 {
959 mutt_endwin();
960 mutt_file_copy_stream(fp_err, stdout);
962 goto cleanup;
963 }
964
965 mutt_file_fclose(&fp_out);
966 cert = buf_strdup(certfile);
967
968cleanup:
969 mutt_file_fclose(&fp_err);
970 if (fp_out)
971 {
972 mutt_file_fclose(&fp_out);
973 mutt_file_unlink(buf_string(certfile));
974 }
975 buf_pool_release(&certfile);
976 return cert;
977}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_encrypt()

static pid_t smime_invoke_encrypt ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname,
const char * uids )
static

Use SMIME to encrypt a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
[in]uidsList of IDs/fingerprints, space separated
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1142 of file smime.c.

1146{
1147 const char *const c_smime_encrypt_with = cs_subset_string(NeoMutt->sub, "smime_encrypt_with");
1148 const struct Expando *c_smime_encrypt_command = cs_subset_expando(NeoMutt->sub, "smime_encrypt_command");
1149 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1150 fp_smime_outfd, fp_smime_errfd, fname, NULL, c_smime_encrypt_with,
1151 NULL, NULL, uids, NULL, c_smime_encrypt_command);
1152}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_sign()

static pid_t smime_invoke_sign ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname )
static

Use SMIME to sign a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1169 of file smime.c.

1172{
1174 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1175 const struct Expando *c_smime_sign_command = cs_subset_expando(NeoMutt->sub, "smime_sign_command");
1176 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1177 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL,
1178 c_smime_sign_digest_alg, buf_string(&mod_data->smime_key_to_use),
1179 buf_string(&mod_data->smime_cert_to_use),
1180 buf_string(&mod_data->smime_intermediate_to_use), c_smime_sign_command);
1181}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ openssl_md_to_smime_micalg()

static char * openssl_md_to_smime_micalg ( const char * md)
static

Change the algorithm names.

Parameters
mdOpenSSL message digest name
Return values
ptrSMIME Message Integrity Check algorithm

The openssl -md doesn't want hyphens: md5, sha1, sha224, sha256, sha384, sha512 However, the micalg does: md5, sha-1, sha-224, sha-256, sha-384, sha-512

Note
The caller should free the returned string

Definition at line 1330 of file smime.c.

1331{
1332 if (!md)
1333 return NULL;
1334
1335 char *micalg = NULL;
1336 if (mutt_istr_startswith(md, "sha"))
1337 {
1338 mutt_str_asprintf(&micalg, "sha-%s", md + 3);
1339 }
1340 else
1341 {
1342 micalg = mutt_str_dup(md);
1343 }
1344
1345 return micalg;
1346}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:808
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_verify()

static pid_t smime_invoke_verify ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname,
const char * sig_fname,
int opaque )
static

Use SMIME to verify a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
[in]sig_fnameSignature filename to pass to the command
[in]opaqueIf true, use $smime_verify_opaque_command else $smime_verify_command
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1523 of file smime.c.

1527{
1528 const struct Expando *c_smime_verify_opaque_command =
1529 cs_subset_expando(NeoMutt->sub, "smime_verify_opaque_command");
1530 const struct Expando *c_smime_verify_command = cs_subset_expando(NeoMutt->sub, "smime_verify_command");
1531 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1532 fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1533 (opaque ? c_smime_verify_opaque_command : c_smime_verify_command));
1534}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_decrypt()

static pid_t smime_invoke_decrypt ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname )
static

Use SMIME to decrypt a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1551 of file smime.c.

1554{
1556 const struct Expando *c_smime_decrypt_command = cs_subset_expando(NeoMutt->sub, "smime_decrypt_command");
1557 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1558 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1559 buf_string(&mod_data->smime_key_to_use),
1560 buf_string(&mod_data->smime_cert_to_use), NULL,
1561 c_smime_decrypt_command);
1562}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_handle_entity()

static struct Body * smime_handle_entity ( struct Body * b,
struct State * state,
FILE * fp_out_file )
static

Handle type application/pkcs7-mime.

Parameters
bBody to handle
stateState to use
fp_out_fileFile for the result
Return values
ptrBody for parsed MIME part

This can either be a signed or an encrypted message.

Definition at line 1681 of file smime.c.

1682{
1684 struct Buffer *tmpfname = buf_pool_get();
1685 FILE *fp_smime_out = NULL, *fp_smime_in = NULL, *fp_smime_err = NULL;
1686 FILE *fp_tmp = NULL, *fp_out = NULL;
1687 struct Body *p = NULL;
1688 pid_t pid = -1;
1690
1691 if (!(type & APPLICATION_SMIME))
1692 return NULL;
1693
1694 /* Because of the mutt_body_handler() we avoid the buffer pool. */
1695 fp_smime_out = mutt_file_mkstemp();
1696 if (!fp_smime_out)
1697 {
1698 mutt_perror(_("Can't create temporary file"));
1699 goto cleanup;
1700 }
1701
1702 fp_smime_err = mutt_file_mkstemp();
1703 if (!fp_smime_err)
1704 {
1705 mutt_perror(_("Can't create temporary file"));
1706 goto cleanup;
1707 }
1708
1709 buf_mktemp(tmpfname);
1710 fp_tmp = mutt_file_fopen(buf_string(tmpfname), "w+");
1711 if (!fp_tmp)
1712 {
1713 mutt_perror("%s", buf_string(tmpfname));
1714 goto cleanup;
1715 }
1716
1717 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1718 {
1719 goto cleanup;
1720 }
1721
1722 mutt_file_copy_bytes(state->fp_in, fp_tmp, b->length);
1723
1724 fflush(fp_tmp);
1725 mutt_file_fclose(&fp_tmp);
1726
1727 if ((type & SEC_ENCRYPT) &&
1728 ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_smime_out),
1729 fileno(fp_smime_err), buf_string(tmpfname))) == -1))
1730 {
1731 mutt_file_unlink(buf_string(tmpfname));
1732 if (state->flags & STATE_DISPLAY)
1733 {
1734 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1735 }
1736 goto cleanup;
1737 }
1738 else if ((type & SEC_SIGNOPAQUE) &&
1739 ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
1740 fileno(fp_smime_out), fileno(fp_smime_err), NULL,
1741 buf_string(tmpfname), SEC_SIGNOPAQUE)) == -1))
1742 {
1743 mutt_file_unlink(buf_string(tmpfname));
1744 if (state->flags & STATE_DISPLAY)
1745 {
1746 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1747 }
1748 goto cleanup;
1749 }
1750
1751 if (type & SEC_ENCRYPT)
1752 {
1755 fputs(mod_data->smime_pass, fp_smime_in);
1756 fputc('\n', fp_smime_in);
1757 }
1758
1759 mutt_file_fclose(&fp_smime_in);
1760
1761 filter_wait(pid);
1762 mutt_file_unlink(buf_string(tmpfname));
1763
1764 if (state->flags & STATE_DISPLAY)
1765 {
1766 fflush(fp_smime_err);
1767 rewind(fp_smime_err);
1768
1769 const int c = fgetc(fp_smime_err);
1770 if (c != EOF)
1771 {
1772 ungetc(c, fp_smime_err);
1773
1774 crypt_current_time(state, "OpenSSL");
1775 mutt_file_copy_stream(fp_smime_err, state->fp_out);
1776 state_attach_puts(state, _("[-- End of OpenSSL output --]\n\n"));
1777 }
1778
1779 if (type & SEC_ENCRYPT)
1780 {
1781 state_attach_puts(state, _("[-- The following data is S/MIME encrypted --]\n"));
1782 }
1783 else
1784 {
1785 state_attach_puts(state, _("[-- The following data is S/MIME signed --]\n"));
1786 }
1787 }
1788
1789 fflush(fp_smime_out);
1790 rewind(fp_smime_out);
1791
1792 if (type & SEC_ENCRYPT)
1793 {
1794 /* void the passphrase, even if that wasn't the problem */
1795 if (fgetc(fp_smime_out) == EOF)
1796 {
1797 mutt_error(_("Decryption failed"));
1799 }
1800 rewind(fp_smime_out);
1801 }
1802
1803 if (fp_out_file)
1804 {
1805 fp_out = fp_out_file;
1806 }
1807 else
1808 {
1809 fp_out = mutt_file_mkstemp();
1810 if (!fp_out)
1811 {
1812 mutt_perror(_("Can't create temporary file"));
1813 goto cleanup;
1814 }
1815 }
1816 char buf[8192] = { 0 };
1817 while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
1818 {
1819 const size_t len = mutt_str_len(buf);
1820 if ((len > 1) && (buf[len - 2] == '\r'))
1821 {
1822 buf[len - 2] = '\n';
1823 buf[len - 1] = '\0';
1824 }
1825 fputs(buf, fp_out);
1826 }
1827 fflush(fp_out);
1828 rewind(fp_out);
1829
1830 const long size = mutt_file_get_size_fp(fp_out);
1831 if (size == 0)
1832 {
1833 goto cleanup;
1834 }
1835 p = mutt_read_mime_header(fp_out, 0);
1836 if (p)
1837 {
1838 p->length = size - p->offset;
1839
1840 mutt_parse_part(fp_out, p);
1841
1842 if (state->flags & STATE_DISPLAY)
1844
1845 /* Store any protected headers in the parent so they can be
1846 * accessed for index updates after the handler recursion is done.
1847 * This is done before the handler to prevent a nested encrypted
1848 * handler from freeing the headers. */
1850 b->mime_headers = p->mime_headers;
1851 p->mime_headers = NULL;
1852
1853 if (state->fp_out)
1854 {
1855 rewind(fp_out);
1856 FILE *fp_tmp_buffer = state->fp_in;
1857 state->fp_in = fp_out;
1858 mutt_body_handler(p, state);
1859 state->fp_in = fp_tmp_buffer;
1860 }
1861
1862 /* Embedded multipart signed protected headers override the
1863 * encrypted headers. We need to do this after the handler so
1864 * they can be printed in the pager. */
1865 if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
1866 p->parts->mime_headers)
1867 {
1870 p->parts->mime_headers = NULL;
1871 }
1872 }
1873 mutt_file_fclose(&fp_smime_out);
1874
1875 if (!fp_out_file)
1876 {
1877 mutt_file_fclose(&fp_out);
1878 mutt_file_unlink(buf_string(tmpfname));
1879 }
1880 fp_out = NULL;
1881
1882 if (state->flags & STATE_DISPLAY)
1883 {
1884 if (type & SEC_ENCRYPT)
1885 state_attach_puts(state, _("[-- End of S/MIME encrypted data --]\n"));
1886 else
1887 state_attach_puts(state, _("[-- End of S/MIME signed data --]\n"));
1888 }
1889
1890 if (type & SEC_SIGNOPAQUE)
1891 {
1892 char *line = NULL;
1893 size_t linelen;
1894
1895 rewind(fp_smime_err);
1896
1897 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NONE);
1898 if (linelen && mutt_istr_equal(line, "verification successful"))
1899 b->goodsig = true;
1900 FREE(&line);
1901 }
1902 else if (p)
1903 {
1904 b->goodsig = p->goodsig;
1905 b->badsig = p->badsig;
1906 }
1907
1908cleanup:
1909 mutt_file_fclose(&fp_smime_out);
1910 mutt_file_fclose(&fp_smime_err);
1911 mutt_file_fclose(&fp_tmp);
1912 mutt_file_fclose(&fp_out);
1913 buf_pool_release(&tmpfname);
1914 return p;
1915}
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:408
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:609
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition crypt.c:64
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1883
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1420
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
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
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
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
bool smime_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition smime.c:147
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1122
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1664
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
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_SIGNOPAQUE
Email has an opaque signature (encrypted)
Definition lib.h:97
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
#define SMIME_SIGN
Email is S/MIME signed.
Definition lib.h:119
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, int opaque)
Use SMIME to verify a file.
Definition smime.c:1523
static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
Use SMIME to decrypt a file.
Definition smime.c:1551
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
LOFF_T offset
offset where the actual data begins
Definition body.h:52
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition body.h:43
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
bool goodsig
Good cryptographic signature.
Definition body.h:45
unsigned int type
content-type primary type, ContentType
Definition body.h:40
char smime_pass[256]
Cached S/MIME Passphrase.
Definition module_data.h:55
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
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: