From: Kevin McCarthy Date: Tue, 16 Jul 2019 01:36:57 +0000 (-0700) Subject: Add gossip header processing. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a2a2e88524eafdbb49bdfdbdab557953a6cc9372;p=mutt Add gossip header processing. --- diff --git a/autocrypt/autocrypt.c b/autocrypt/autocrypt.c index 5207af4b..73fe5364 100644 --- a/autocrypt/autocrypt.c +++ b/autocrypt/autocrypt.c @@ -23,6 +23,7 @@ #include "mutt.h" #include "mutt_curses.h" #include "mime.h" +#include "mutt_idna.h" #include "autocrypt.h" #include "autocrypt_private.h" @@ -302,3 +303,141 @@ cleanup: return rv; } + +static ADDRESS *matching_gossip_address (ENVELOPE *env, const char *addr) +{ + ADDRESS *cur; + + for (cur = env->to; cur; cur = cur->next) + if (!ascii_strcasecmp (cur->mailbox, addr)) + return cur; + + for (cur = env->cc; cur; cur = cur->next) + if (!ascii_strcasecmp (cur->mailbox, addr)) + return cur; + + for (cur = env->reply_to; cur; cur = cur->next) + if (!ascii_strcasecmp (cur->mailbox, addr)) + return cur; + + return NULL; +} + +int mutt_autocrypt_process_gossip_header (HEADER *hdr, ENVELOPE *env) +{ + AUTOCRYPTHDR *ac_hdr; + struct timeval now; + AUTOCRYPT_PEER *peer = NULL; + AUTOCRYPT_GOSSIP_HISTORY *gossip_hist = NULL; + ADDRESS *peer_addr; + BUFFER *keyid = NULL; + int update_db = 0, insert_db = 0, insert_db_history = 0, import_gpg = 0; + int rv = -1; + + if (!option (OPTAUTOCRYPT)) + return 0; + + if (mutt_autocrypt_init (0)) + return -1; + + if (!hdr || !hdr->content || !env) + return 0; + + if (!env->from) + return 0; + + /* Ignore emails that appear to be more than a week in the future, + * since they can block all future updates during that time. */ + gettimeofday (&now, NULL); + if (hdr->date_sent > (now.tv_sec + 7 * 24 * 60 * 60)) + return 0; + + keyid = mutt_buffer_pool_get (); + + /* To ensure the address headers match the gossip header format */ + mutt_env_to_intl (env, NULL, NULL); + + for (ac_hdr = env->autocrypt_gossip; ac_hdr; ac_hdr = ac_hdr->next) + { + if (ac_hdr->invalid) + continue; + + peer_addr = matching_gossip_address (env, ac_hdr->addr); + if (!peer_addr) + continue; + + if (mutt_autocrypt_db_peer_get (env->from, &peer) < 0) + goto cleanup; + + if (peer) + { + if (hdr->date_sent <= peer->gossip_timestamp) + { + mutt_autocrypt_db_peer_free (&peer); + continue; + } + + update_db = 1; + peer->gossip_timestamp = hdr->date_sent; + if (mutt_strcmp (peer->gossip_keydata, ac_hdr->keydata)) + { + import_gpg = 1; + insert_db_history = 1; + mutt_str_replace (&peer->gossip_keydata, ac_hdr->keydata); + } + } + else + { + import_gpg = 1; + insert_db = 1; + insert_db_history = 1; + } + + if (!peer) + { + peer = mutt_autocrypt_db_peer_new (); + peer->gossip_timestamp = hdr->date_sent; + peer->gossip_keydata = safe_strdup (ac_hdr->keydata); + } + + if (import_gpg) + { + if (mutt_autocrypt_gpgme_import_key (peer->gossip_keydata, keyid)) + goto cleanup; + mutt_str_replace (&peer->gossip_keyid, mutt_b2s (keyid)); + } + + if (insert_db && + mutt_autocrypt_db_peer_insert (peer_addr, peer)) + goto cleanup; + + if (update_db && + mutt_autocrypt_db_peer_update (peer_addr, peer)) + goto cleanup; + + if (insert_db_history) + { + gossip_hist = mutt_autocrypt_db_gossip_history_new (); + gossip_hist->sender_email_addr = safe_strdup (env->from->mailbox); + gossip_hist->email_msgid = safe_strdup (env->message_id); + gossip_hist->timestamp = hdr->date_sent; + gossip_hist->gossip_keydata = safe_strdup (peer->gossip_keydata); + if (mutt_autocrypt_db_gossip_history_insert (peer_addr, gossip_hist)) + goto cleanup; + } + + mutt_autocrypt_db_peer_free (&peer); + mutt_autocrypt_db_gossip_history_free (&gossip_hist); + mutt_buffer_clear (keyid); + update_db = insert_db = insert_db_history = import_gpg = 0; + } + + rv = 0; + +cleanup: + mutt_autocrypt_db_peer_free (&peer); + mutt_autocrypt_db_gossip_history_free (&gossip_hist); + mutt_buffer_pool_release (&keyid); + + return rv; +} diff --git a/autocrypt/autocrypt.h b/autocrypt/autocrypt.h index 859a708a..a2401bc3 100644 --- a/autocrypt/autocrypt.h +++ b/autocrypt/autocrypt.h @@ -53,8 +53,18 @@ typedef struct char *keydata; } AUTOCRYPT_PEER_HISTORY; +typedef struct +{ + char *peer_email_addr; + char *sender_email_addr; + char *email_msgid; + sqlite3_int64 timestamp; + char *gossip_keydata; +} AUTOCRYPT_GOSSIP_HISTORY; + int mutt_autocrypt_init (int); void mutt_autocrypt_cleanup (void); int mutt_autocrypt_process_autocrypt_header (HEADER *hdr, ENVELOPE *env); +int mutt_autocrypt_process_gossip_header (HEADER *hdr, ENVELOPE *env); #endif diff --git a/autocrypt/autocrypt_db.c b/autocrypt/autocrypt_db.c index d549d678..8b0ff0b3 100644 --- a/autocrypt/autocrypt_db.c +++ b/autocrypt/autocrypt_db.c @@ -32,6 +32,7 @@ static sqlite3_stmt *PeerGetStmt; static sqlite3_stmt *PeerInsertStmt; static sqlite3_stmt *PeerUpdateStmt; static sqlite3_stmt *PeerHistoryInsertStmt; +static sqlite3_stmt *GossipHistoryInsertStmt; static int autocrypt_db_create (const char *db_path) { @@ -114,6 +115,9 @@ void mutt_autocrypt_db_close (void) sqlite3_finalize (PeerHistoryInsertStmt); PeerHistoryInsertStmt = NULL; + sqlite3_finalize (GossipHistoryInsertStmt); + GossipHistoryInsertStmt = NULL; + sqlite3_close_v2 (AutocryptDB); AutocryptDB = NULL; } @@ -611,3 +615,83 @@ cleanup: sqlite3_reset (PeerHistoryInsertStmt); return rv; } + +AUTOCRYPT_GOSSIP_HISTORY *mutt_autocrypt_db_gossip_history_new (void) +{ + return safe_calloc (1, sizeof(AUTOCRYPT_GOSSIP_HISTORY)); +} + +void mutt_autocrypt_db_gossip_history_free (AUTOCRYPT_GOSSIP_HISTORY **gossip_hist) +{ + if (!gossip_hist || !*gossip_hist) + return; + FREE (&(*gossip_hist)->peer_email_addr); + FREE (&(*gossip_hist)->sender_email_addr); + FREE (&(*gossip_hist)->email_msgid); + FREE (&(*gossip_hist)->gossip_keydata); + FREE (gossip_hist); /* __FREE_CHECKED__ */ +} + +int mutt_autocrypt_db_gossip_history_insert (ADDRESS *addr, AUTOCRYPT_GOSSIP_HISTORY *gossip_hist) +{ + int rv = -1; + char *email = NULL; + + email = normalize_email_addr (addr); + + if (!GossipHistoryInsertStmt) + { + if (sqlite3_prepare_v3 ( + AutocryptDB, + "INSERT INTO gossip_history " + "(peer_email_addr, " + "sender_email_addr, " + "email_msgid, " + "timestamp, " + "gossip_keydata) " + "VALUES (?, ?, ?, ?, ?);", + -1, + SQLITE_PREPARE_PERSISTENT, + &GossipHistoryInsertStmt, + NULL) != SQLITE_OK) + goto cleanup; + } + + if (sqlite3_bind_text (GossipHistoryInsertStmt, + 1, + email, + -1, + SQLITE_STATIC) != SQLITE_OK) + goto cleanup; + if (sqlite3_bind_text (GossipHistoryInsertStmt, + 2, + gossip_hist->sender_email_addr, + -1, + SQLITE_STATIC) != SQLITE_OK) + if (sqlite3_bind_text (GossipHistoryInsertStmt, + 3, + gossip_hist->email_msgid, + -1, + SQLITE_STATIC) != SQLITE_OK) + goto cleanup; + if (sqlite3_bind_int64 (GossipHistoryInsertStmt, + 4, + gossip_hist->timestamp) != SQLITE_OK) + goto cleanup; + if (sqlite3_bind_text (GossipHistoryInsertStmt, + 5, + gossip_hist->gossip_keydata, + -1, + SQLITE_STATIC) != SQLITE_OK) + goto cleanup; + + if (sqlite3_step (GossipHistoryInsertStmt) != SQLITE_DONE) + goto cleanup; + + rv = 0; + +cleanup: + FREE (&email); + sqlite3_reset (GossipHistoryInsertStmt); + return rv; +} diff --git a/autocrypt/autocrypt_private.h b/autocrypt/autocrypt_private.h index d43c9e83..de8638f9 100644 --- a/autocrypt/autocrypt_private.h +++ b/autocrypt/autocrypt_private.h @@ -42,6 +42,10 @@ AUTOCRYPT_PEER_HISTORY *mutt_autocrypt_db_peer_history_new (void); void mutt_autocrypt_db_peer_history_free (AUTOCRYPT_PEER_HISTORY **peerhist); int mutt_autocrypt_db_peer_history_insert (ADDRESS *addr, AUTOCRYPT_PEER_HISTORY *peerhist); +AUTOCRYPT_GOSSIP_HISTORY *mutt_autocrypt_db_gossip_history_new (void); +void mutt_autocrypt_db_gossip_history_free (AUTOCRYPT_GOSSIP_HISTORY **gossip_hist); +int mutt_autocrypt_db_gossip_history_insert (ADDRESS *addr, AUTOCRYPT_GOSSIP_HISTORY *gossip_hist); + int mutt_autocrypt_schema_init (void); int mutt_autocrypt_schema_update (void); diff --git a/commands.c b/commands.c index ac8a120b..902e3f2a 100644 --- a/commands.c +++ b/commands.c @@ -41,6 +41,10 @@ #include "imap.h" #endif +#ifdef USE_AUTOCRYPT +#include "autocrypt/autocrypt.h" +#endif + #include "buffy.h" #include @@ -57,12 +61,16 @@ static const char *ExtPagerProgress = "all"; /* The folder the user last saved to. Used by ci_save_message() */ static char LastSaveFolder[_POSIX_PATH_MAX] = ""; -static void update_protected_headers (HEADER *cur) +static void process_protected_headers (HEADER *cur) { ENVELOPE *prot_headers = NULL; regmatch_t pmatch[1]; - if (!option (OPTCRYPTPROTHDRSREAD)) + if (!option (OPTCRYPTPROTHDRSREAD) +#ifdef USE_AUTOCRYPT + && !option (OPTAUTOCRYPT) +#endif + ) return; /* Grab protected headers to update in the index */ @@ -104,7 +112,8 @@ static void update_protected_headers (HEADER *cur) } /* Update protected headers in the index and header cache. */ - if (prot_headers && + if (option (OPTCRYPTPROTHDRSREAD) && + prot_headers && prot_headers->subject && mutt_strcmp (cur->env->subject, prot_headers->subject)) { @@ -131,6 +140,16 @@ static void update_protected_headers (HEADER *cur) Context->changed = 1; } } + +#ifdef USE_AUTOCRYPT + if (option (OPTAUTOCRYPT) && + (cur->security & ENCRYPT) && + prot_headers && + prot_headers->autocrypt_gossip) + { + mutt_autocrypt_process_gossip_header (cur, cur->env); + } +#endif } int mutt_display_message (HEADER *cur) @@ -253,8 +272,8 @@ int mutt_display_message (HEADER *cur) are color patterns for both ~g and ~V */ cur->pair = 0; - /* Grab protected headers and update the header and index */ - update_protected_headers (cur); + /* Process protected headers and autocrypt gossip headers */ + process_protected_headers (cur); } if (builtin) diff --git a/mutt.h b/mutt.h index d15ab106..7bd2be28 100644 --- a/mutt.h +++ b/mutt.h @@ -708,6 +708,7 @@ typedef struct envelope LIST *userhdrs; /* user defined headers */ #ifdef USE_AUTOCRYPT AUTOCRYPTHDR *autocrypt; + AUTOCRYPTHDR *autocrypt_gossip; #endif unsigned char changed; /* The MUTT_ENV_CHANGED_* flags specify which * fields are modified */ diff --git a/muttlib.c b/muttlib.c index c31817cc..ba8f9970 100644 --- a/muttlib.c +++ b/muttlib.c @@ -827,6 +827,7 @@ void mutt_free_envelope (ENVELOPE **p) #ifdef USE_AUTOCRYPT mutt_free_autocrypthdr (&(*p)->autocrypt); + mutt_free_autocrypthdr (&(*p)->autocrypt_gossip); #endif FREE (p); /* __FREE_CHECKED__ */ diff --git a/parse.c b/parse.c index 8dd9240a..777e7a64 100644 --- a/parse.c +++ b/parse.c @@ -1141,6 +1141,14 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short matched = 1; } } + else if (ascii_strcasecmp (line+1, "utocrypt-gossip") == 0) + { + if (option (OPTAUTOCRYPT)) + { + e->autocrypt_gossip = parse_autocrypt (e->autocrypt_gossip, p); + matched = 1; + } + } #endif break;