X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=crypt.c;h=e137f2c4224da8a1ab78ee54c174c14600daafff;hp=d044e9ab3aac31f796a9c142054765a44e2d8d0c;hb=1d2617e5d89468db7cd1b93fd2b31af73cd7c8ff;hpb=7d9dec2f12342892c972bed1ece496b03180cd81 diff --git a/crypt.c b/crypt.c index d044e9a..e137f2c 100644 --- a/crypt.c +++ b/crypt.c @@ -22,8 +22,6 @@ #include #include "crypt.h" - -#include "lib.h" #include "alias.h" #include "handler.h" #include "copy.h" @@ -38,459 +36,365 @@ #define CRYPT_KV_STRONGID 8 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING) -/* - * Type definitions. - */ - -struct crypt_cache { - char *what; - char *dflt; - struct crypt_cache *next; -}; - struct dn_array_s { - char *key; - char *value; + char *key; + char *value; }; /* We work based on user IDs, getting from a user ID to the key is check and does not need any memory (gpgme uses reference counting). */ -typedef struct crypt_keyinfo { - struct crypt_keyinfo *next; - gpgme_key_t kobj; - int idx; /* and the user ID at this index */ - const char *uid; /* and for convenience point to this user ID */ - unsigned int flags; /* global and per uid flags (for convenience) */ -} crypt_key_t; +typedef struct cryptkey_t { + struct cryptkey_t *next; + int idx; /* and the user ID at this index */ + int flags; /* global and per uid flags (for convenience) */ + gpgme_key_t kobj; + const char *uid; /* and for convenience point to this user ID */ +} cryptkey_t; + +DO_INIT(cryptkey_t, cryptkey); +static void cryptkey_wipe(cryptkey_t *key) { + gpgme_key_release(key->kobj); +} +DO_NEW(cryptkey_t, cryptkey); +DO_DELETE(cryptkey_t, cryptkey); +DO_SLIST(cryptkey_t, key, cryptkey_delete); + +static cryptkey_t *cryptkey_dup(const cryptkey_t *k) +{ + cryptkey_t *res = cryptkey_new(); + *res = *k; + res->next = NULL; + gpgme_key_ref(k->kobj); + return res; +} typedef struct crypt_entry { - ssize_t num; - crypt_key_t *key; + ssize_t num; + cryptkey_t *key; } crypt_entry_t; - -static struct crypt_cache *id_defaults = NULL; static gpgme_key_t signature_key = NULL; -/* - * General helper functions. - */ - static void convert_to_7bit (BODY * a) { - while (a) { - if (a->type == TYPEMULTIPART) { - if (a->encoding != ENC7BIT) { - a->encoding = ENC7BIT; - convert_to_7bit (a->parts); - } else { - convert_to_7bit (a->parts); - } - } - else if (a->type == TYPEMESSAGE && - m_strcasecmp(a->subtype, "delivery-status")) { - if (a->encoding != ENC7BIT) - mutt_message_to_7bit (a, NULL); + for (; a; a = a->next) { + int tok = mime_which_token(a->subtype, -1); + + if (a->type == TYPEMULTIPART) { + a->encoding = ENC7BIT; + convert_to_7bit(a->parts); + } else if (a->type == TYPEMESSAGE && tok == MIME_DELIVERY_STATUS) { + if (a->encoding != ENC7BIT) + mutt_message_to_7bit(a, NULL); + } else if (a->encoding == ENC8BIT) { + a->encoding = ENCQUOTEDPRINTABLE; + } else if (a->encoding == ENCBINARY) { + a->encoding = ENCBASE64; + } else if (a->content && a->encoding != ENCBASE64 + && (a->content->from || a->content->space)) + { + a->encoding = ENCQUOTEDPRINTABLE; + } } - else if (a->encoding == ENC8BIT) - a->encoding = ENCQUOTEDPRINTABLE; - else if (a->encoding == ENCBINARY) - a->encoding = ENCBASE64; - else if (a->content && a->encoding != ENCBASE64 && - (a->content->from || a->content->space)) - a->encoding = ENCQUOTEDPRINTABLE; - a = a->next; - } -} - - -/* return true when S points to a didgit or letter. */ -static int digit_or_letter (const unsigned char *s) -{ - return ((*s >= '0' && *s <= '9') - || (*s >= 'A' && *s <= 'Z') - || (*s >= 'a' && *s <= 'z')); } - /* Print the utf-8 encoded string BUF of length LEN bytes to stream FP. Convert the character set. */ static void print_utf8 (FILE * fp, const char *buf, ssize_t len) { - char *tstr; + char *tstr; - tstr = p_dupstr(buf, len); - mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM); - fputs (tstr, fp); - p_delete(&tstr); + tstr = p_dupstr(buf, len); + mutt_convert_string(&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM); + fputs(tstr, fp); + p_delete(&tstr); } - -/* - * Key management. - */ - /* Return the keyID for the key K. Note that this string is valid as long as K is valid */ -static const char *crypt_keyid (crypt_key_t * k) +static const char *crypt_keyid (cryptkey_t * k) { - const char *s = "????????"; - - if (k->kobj && k->kobj->subkeys) { - s = k->kobj->subkeys->keyid; - if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16)) - /* Return only the short keyID. */ - s += 8; - } + if (k->kobj && k->kobj->subkeys) { + const char *s = k->kobj->subkeys->keyid; + return m_strlen(s) == 16 ? s + 8 : s; + } - return s; + return "????????"; } /* Return the hexstring fingerprint from the key K. */ -static const char *crypt_fpr (crypt_key_t * k) +static const char *crypt_fpr (cryptkey_t * k) { - const char *s = ""; - - if (k->kobj && k->kobj->subkeys) - s = k->kobj->subkeys->fpr; - - return s; + return k->kobj && k->kobj->subkeys ? k->kobj->subkeys->fpr : ""; } /* Parse FLAGS and return a statically allocated(!) string with them. */ static char *crypt_key_abilities (int flags) { - static char buff[3]; + static char buff[3] = "es"; - if (!(flags & KEYFLAG_CANENCRYPT)) - buff[0] = '-'; - else if (flags & KEYFLAG_PREFER_SIGNING) - buff[0] = '.'; - else - buff[0] = 'e'; - - if (!(flags & KEYFLAG_CANSIGN)) - buff[1] = '-'; - else if (flags & KEYFLAG_PREFER_ENCRYPTION) - buff[1] = '.'; - else - buff[1] = 's'; + if (!(flags & KEYFLAG_CANENCRYPT)) + buff[0] = '-'; + else if (flags & KEYFLAG_PREFER_SIGNING) + buff[0] = '.'; - buff[2] = '\0'; + if (!(flags & KEYFLAG_CANSIGN)) + buff[1] = '-'; + else if (flags & KEYFLAG_PREFER_ENCRYPTION) + buff[1] = '.'; - return buff; + return buff; } /* Parse FLAGS and return a character describing the most important flag. */ -static char crypt_flags (int flags) -{ - if (flags & KEYFLAG_REVOKED) - return 'R'; - else if (flags & KEYFLAG_EXPIRED) - return 'X'; - else if (flags & KEYFLAG_DISABLED) - return 'd'; - else if (flags & KEYFLAG_CRITICAL) - return 'c'; - else +static char crypt_flags(int flags) +{ + if (flags & KEYFLAG_REVOKED) + return 'R'; + if (flags & KEYFLAG_EXPIRED) + return 'X'; + if (flags & KEYFLAG_DISABLED) + return 'd'; + if (flags & KEYFLAG_CRITICAL) + return 'c'; return ' '; } -/* Return a copy of KEY. */ -static crypt_key_t *crypt_copy_key (crypt_key_t *key) -{ - crypt_key_t *k; - - k = p_new(crypt_key_t, 1); - k->kobj = key->kobj; - gpgme_key_ref (key->kobj); - k->idx = key->idx; - k->uid = key->uid; - k->flags = key->flags; - - return k; -} - -/* Release all the keys at the address of KEYLIST and set the address - to NULL. */ -static void crypt_free_key (crypt_key_t ** keylist) -{ - while (*keylist) { - crypt_key_t *k = (*keylist)->next; - - p_delete(&k); - *keylist = k; - } -} - -/* Return trute when key K is valid. */ -static int crypt_key_is_valid (crypt_key_t * k) -{ - if (k->flags & KEYFLAG_CANTUSE) - return 0; - return 1; -} - /* Return true whe validity of KEY is sufficient. */ -static int crypt_id_is_strong (crypt_key_t * key) +static int crypt_id_is_strong (cryptkey_t * key) { - gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN; - gpgme_user_id_t uid = NULL; - int is_strong = 0; - int i = 0; - - if ((key->flags & KEYFLAG_ISX509)) - return 1; - - for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid; - i++, uid = uid->next); - if (uid) - val = uid->validity; - - switch (val) { - case GPGME_VALIDITY_UNKNOWN: - case GPGME_VALIDITY_UNDEFINED: - case GPGME_VALIDITY_NEVER: - case GPGME_VALIDITY_MARGINAL: - is_strong = 0; - break; + gpgme_user_id_t uid; + int i; - case GPGME_VALIDITY_FULL: - case GPGME_VALIDITY_ULTIMATE: - is_strong = 1; - break; - } + if (key->flags & KEYFLAG_ISX509) + return 1; - return is_strong; -} + for (i = 0, uid = key->kobj->uids; uid; i++, uid = uid->next) { + if (i == key->idx) { + return uid->validity == GPGME_VALIDITY_FULL + || uid->validity == GPGME_VALIDITY_ULTIMATE; + } + } -/* Return true when the KEY is valid, i.e. not marked as unusable. */ -static int crypt_id_is_valid (crypt_key_t * key) -{ - return !(key->flags & KEYFLAG_CANTUSE); + return 0; } /* Return a bit vector describing how well the addresses ADDR and U_ADDR match and whether KEY is valid. */ -static int crypt_id_matches_addr (address_t * addr, address_t * u_addr, - crypt_key_t * key) +static int +crypt_id_matches_addr(address_t *addr, address_t *u_addr, cryptkey_t *key) { - int rv = 0; + int rv = 0; - if (crypt_id_is_valid (key)) - rv |= CRYPT_KV_VALID; + if (!(key->flags & KEYFLAG_CANTUSE)) + rv |= CRYPT_KV_VALID; - if (crypt_id_is_strong (key)) - rv |= CRYPT_KV_STRONGID; + if (crypt_id_is_strong(key)) + rv |= CRYPT_KV_STRONGID; - if (addr->mailbox && u_addr->mailbox - && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0) - rv |= CRYPT_KV_ADDR; + if (addr->mailbox && !m_strcasecmp(addr->mailbox, u_addr->mailbox)) + rv |= CRYPT_KV_ADDR; - if (addr->personal && u_addr->personal - && m_strcasecmp(addr->personal, u_addr->personal) == 0) - rv |= CRYPT_KV_STRING; + if (addr->personal && m_strcasecmp(addr->personal, u_addr->personal)) + rv |= CRYPT_KV_STRING; - return rv; + return rv; } -/* - * GPGME convenient functions. - */ - /* Create a new gpgme context and return it. With FOR_SMIME set to true, the protocol of the context is set to CMS. */ -static gpgme_ctx_t create_gpgme_context (int for_smime) +static gpgme_ctx_t create_gpgme_context(int for_smime) { - gpgme_error_t err; - gpgme_ctx_t ctx; - - err = gpgme_new (&ctx); - if (err) { - mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err)); - sleep (2); - mutt_exit (1); - } + gpgme_error_t err; + gpgme_ctx_t ctx; - if (for_smime) { - err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS); + err = gpgme_new (&ctx); if (err) { - mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err)); - sleep (2); - mutt_exit (1); + mutt_error(_("error creating gpgme context: %s\n"), + gpgme_strerror(err)); + sleep(2); + mutt_exit(1); } - } + if (!for_smime) + return ctx; - return ctx; + err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS); + if (err) { + mutt_error(_("error enabling CMS protocol: %s\n"), gpgme_strerror(err)); + sleep(2); + mutt_exit(1); + } + return ctx; } /* Create a new gpgme data object. This is a wrapper to die on error. */ -static gpgme_data_t create_gpgme_data (void) +static gpgme_data_t create_gpgme_data(void) { - gpgme_error_t err; - gpgme_data_t data; + gpgme_error_t err; + gpgme_data_t data; - err = gpgme_data_new (&data); - if (err) { - mutt_error (_("error creating gpgme data object: %s\n"), - gpgme_strerror (err)); - sleep (2); - mutt_exit (1); - } - return data; + err = gpgme_data_new(&data); + if (err) { + mutt_error(_("error creating gpgme data object: %s\n"), + gpgme_strerror(err)); + sleep(2); + mutt_exit(1); + } + return data; } /* Create a new GPGME Data object from the mail body A. With CONVERT passed as true, the lines are converted to CR,LF if required. Return NULL on error or the gpgme_data_t object on success. */ -static gpgme_data_t body_to_data_object (BODY * a, int convert) +static gpgme_data_t body_to_data_object(BODY *a, int convert) { - char tempfile[_POSIX_PATH_MAX]; - FILE *fptmp; - int err = 0; - gpgme_data_t data; + gpgme_data_t data; + FILE *fptmp; + int err = 0; - fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); - if (!fptmp) { - mutt_perror (_("Can't create temporary file")); - return NULL; - } + if (!(fptmp = tmpfile())) { + mutt_perror (_("Can't create temporary file")); + return NULL; + } - mutt_write_mime_header (a, fptmp); - fputc ('\n', fptmp); - mutt_write_mime_body (a, fptmp); + mutt_write_mime_header(a, fptmp); + fputc('\n', fptmp); + mutt_write_mime_body(a, fptmp); + rewind(fptmp); - if (convert) { - int c, hadcr = 0; - unsigned char buf[1]; + if (convert) { + char buf[STRING]; + int spare = 0; - data = create_gpgme_data (); - rewind (fptmp); - while ((c = fgetc (fptmp)) != EOF) { - if (c == '\r') - hadcr = 1; - else { - if (c == '\n' && !hadcr) { - buf[0] = '\r'; - gpgme_data_write (data, buf, 1); - } + data = create_gpgme_data(); - hadcr = 0; - } - /* FIXME: This is quite suboptimal */ - buf[0] = c; - gpgme_data_write (data, buf, 1); + while (fgets(buf + spare, sizeof(buf) - 1, fptmp)) { + int l = m_strlen(buf); + + spare = buf[l - 1] != '\n'; + if (!spare && (l <= 1 || buf[l - 2] != '\r')) { + buf[l - 1] = '\r'; + buf[l++] = '\n'; + } + gpgme_data_write(data, buf, l - spare); + if (spare) + buf[0] = buf[l - 1]; + } + if (spare) + gpgme_data_write(data, buf, 1); + gpgme_data_seek(data, 0, SEEK_SET); + m_fclose(&fptmp); + return data; } - gpgme_data_seek (data, 0, SEEK_SET); - } else { - err = gpgme_data_new_from_file (&data, tempfile, 1); - } - m_fclose(&fptmp); - unlink (tempfile); - if (err) { - mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err)); - return NULL; - } - return data; + err = gpgme_data_new_from_stream(&data, fptmp); + m_fclose(&fptmp); + if (err) { + mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err)); + return NULL; + } + return data; } /* Create a GPGME data object from the stream FP but limit the object to LENGTH bytes starting at OFFSET bytes from the beginning of the file. */ -static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length) +static gpgme_data_t file_to_data_object(FILE *fp, long offset, long length) { - int err = 0; - gpgme_data_t data; + int err = 0; + gpgme_data_t data; - err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length); - if (err) { - mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err)); - return NULL; - } + err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length); + if (err) { + mutt_error(_("error allocating data object: %s\n"), + gpgme_strerror(err)); + return NULL; + } - return data; + return data; } /* Write a GPGME data object to the stream FP. */ -static int data_object_to_stream (gpgme_data_t data, FILE * fp) +static int data_object_to_stream(gpgme_data_t data, FILE *fp) { - int err; - char buf[4096], *p; - ssize_t nread; - - err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) - ? gpgme_error_from_errno (errno) : 0); - if (err) { - mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err)); - return -1; - } + int err; + char buf[4096], *p; + ssize_t nread; - while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) { - /* fixme: we are not really converting CRLF to LF but just - skipping CR. Doing it correctly needs a more complex logic */ - for (p = buf; nread; p++, nread--) { - if (*p != '\r') - putc (*p, fp); + err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) + ? gpgme_error_from_errno (errno) : 0); + if (err) { + mutt_error (_("error rewinding data object: %s\n"), + gpgme_strerror(err)); + return -1; } - if (ferror (fp)) { - mutt_perror ("[tempfile]"); - return -1; + while ((nread = gpgme_data_read(data, buf, sizeof(buf)))) { + /* fixme: we are not really converting CRLF to LF but just + skipping CR. Doing it correctly needs a more complex logic */ + for (p = buf; nread; p++, nread--) { + if (*p != '\r') + putc (*p, fp); + } + + if (ferror(fp)) { + mutt_perror ("[tempfile]"); + return -1; + } } - } - if (nread == -1) { - mutt_error (_("error reading data object: %s\n"), strerror (errno)); - return -1; - } - return 0; + if (nread == -1) { + mutt_error(_("error reading data object: %s\n"), strerror(errno)); + return -1; + } + return 0; } /* Copy a data object to a newly created temporay file and return that filename. Caller must free. With RET_FP not NULL, don't close the stream but return it there. */ -static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp) +static char *data_object_to_tempfile(gpgme_data_t data, FILE **ret_fp) { - int err; - char tempfile[_POSIX_PATH_MAX]; - FILE *fp; - ssize_t nread = 0; + int err; + char tempfile[_POSIX_PATH_MAX]; + FILE *fp; + ssize_t nread = 0; - fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); - if (!fp) { - mutt_perror (_("Can't create temporary file")); - return NULL; - } + fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); + if (!fp) { + mutt_perror (_("Can't create temporary file")); + return NULL; + } - err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) - ? gpgme_error_from_errno (errno) : 0); - if (!err) { - char buf[4096]; + err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) + ? gpgme_error_from_errno (errno) : 0); + if (!err) { + char buf[4096]; + + while ((nread = gpgme_data_read(data, buf, sizeof(buf)))) { + if (fwrite (buf, nread, 1, fp) != 1) { + mutt_perror (_("Can't create temporary file")); + m_fclose(&fp); + unlink (tempfile); + return NULL; + } + } + } - while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) { - if (fwrite (buf, nread, 1, fp) != 1) { - mutt_perror (_("Can't create temporary file")); - m_fclose(&fp); + if (nread == -1) { + mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err)); unlink (tempfile); + m_fclose(&fp); return NULL; - } } - } - if (ret_fp) - rewind (fp); - else - m_fclose(&fp); - if (nread == -1) { - mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err)); - unlink (tempfile); - m_fclose(&fp); - return NULL; - } - if (ret_fp) - *ret_fp = fp; - return m_strdup(tempfile); + if (ret_fp) { + rewind(fp); + *ret_fp = fp; + } else { + m_fclose(&fp); + } + return m_strdup(tempfile); } @@ -523,110 +427,80 @@ gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key, /* Create a GpgmeRecipientSet from the keys in the string KEYLIST. The keys must be space delimited. */ -static gpgme_key_t *create_recipient_set (const char *keylist, - gpgme_protocol_t protocol) -{ - int err; - const char *s; - char buf[100]; - int i; - gpgme_key_t *rset = NULL; - unsigned int rset_n = 0; - gpgme_key_t key = NULL; - gpgme_ctx_t context = NULL; - - err = gpgme_new (&context); - if (!err) - err = gpgme_set_protocol (context, protocol); - - if (!err) { - s = keylist; - do { - while (*s == ' ') - s++; - for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;) - buf[i++] = *s++; - buf[i] = 0; - if (*buf) { - if (i > 1 && buf[i - 1] == '!') { - /* The user selected to override the valididy of that - key. */ - buf[i - 1] = 0; - - err = gpgme_get_key2 (context, buf, &key, 0); - if (!err) - key->uids->validity = GPGME_VALIDITY_FULL; - buf[i - 1] = '!'; +static gpgme_key_t *create_recipient_set(const char *s, int smime) +{ + gpgme_ctx_t ctx = create_gpgme_context(smime); + gpgme_key_t *rset = NULL; + int rset_n = 0; + + s = skipspaces(s); + while (*s) { + gpgme_error_t err; + gpgme_key_t key; + const char *p = m_strnextsp(s); + char buf[100]; + + m_strncpy(buf, sizeof(buf), s, p - s); + if (p - s > 1 && p[-1] == '!') { + /* user wants to override the valididy of that key. */ + + buf[p - s - 1] = '\0'; + err = gpgme_get_key2(ctx, buf, &key, 0); + if (!err) + key->uids->validity = GPGME_VALIDITY_FULL; + } else { + err = gpgme_get_key2(ctx, buf, &key, 0); } - else - err = gpgme_get_key2 (context, buf, &key, 0); - if (!err) { - p_realloc(&rset, rset_n + 1); - rset[rset_n++] = key; - } - else { - mutt_error (_("error adding recipient `%s': %s\n"), - buf, gpgme_strerror (err)); - p_delete(&rset); - return NULL; + if (err) { + mutt_error(_("error adding recipient `%.*s': %s\n"), + (int)(p - s), s, gpgme_strerror(err)); + p_delete(&rset); + break; } - } - } while (*s); - } - /* NULL terminate. */ - p_realloc(&rset, rset_n + 1); - rset[rset_n++] = NULL; + p_realloc(&rset, rset_n + 1); + rset[rset_n++] = key; + s = skipspaces(p); + } - if (context) - gpgme_release (context); + if (rset) { + /* NULL terminate. */ + p_realloc(&rset, rset_n + 1); + rset[rset_n++] = NULL; + } - return rset; + gpgme_release(ctx); + return rset; } /* Make sure that the correct signer is set. Returns 0 on success. */ -static int set_signer (gpgme_ctx_t ctx, int for_smime) +static int set_signer(gpgme_ctx_t ctx, int for_smime) { - char *signid = for_smime ? SmimeDefaultKey : PgpSignAs; - gpgme_error_t err; - gpgme_ctx_t listctx; - gpgme_key_t key, key2; + const char *signid = for_smime ? SmimeDefaultKey : PgpSignAs; + gpgme_error_t err; + gpgme_key_t key; - if (!signid || !*signid) - return 0; + if (m_strisempty(signid)) + return 0; - listctx = create_gpgme_context (for_smime); - err = gpgme_op_keylist_start (listctx, signid, 1); - if (!err) - err = gpgme_op_keylist_next (listctx, &key); - if (err) { - gpgme_release (listctx); - mutt_error (_("secret key `%s' not found: %s\n"), - signid, gpgme_strerror (err)); - return -1; - } - err = gpgme_op_keylist_next (listctx, &key2); - if (!err) { - gpgme_key_release (key); - gpgme_key_release (key2); - gpgme_release (listctx); - mutt_error (_("ambiguous specification of secret key `%s'\n"), signid); - return -1; - } - gpgme_op_keylist_end (listctx); - gpgme_release (listctx); + err = gpgme_get_key(ctx, signid, &key, 1); + if (err) { + mutt_error(_("error getting secret key `%s': %s\n"), signid, + gpgme_strerror(err)); + return -1; + } - gpgme_signers_clear (ctx); - err = gpgme_signers_add (ctx, key); - gpgme_key_release (key); - if (err) { - mutt_error (_("error setting secret key `%s': %s\n"), - signid, gpgme_strerror (err)); - return -1; - } - return 0; + gpgme_signers_clear(ctx); + err = gpgme_signers_add(ctx, key); + gpgme_key_unref(key); + if (err) { + mutt_error(_("error setting secret key `%s': %s\n"), signid, + gpgme_strerror(err)); + return -1; + } + return 0; } @@ -635,45 +509,46 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime) enciphered text. With USE_SMIME set to true, the smime backend is used. With COMBINED_SIGNED a PGP message is signed and encrypted. Returns NULL in case of error */ -static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset, - int use_smime, int combined_signed) +static char *encrypt_gpgme_object(gpgme_data_t plaintext, gpgme_key_t *rset, + int use_smime, int combined_signed) { - int err; - gpgme_ctx_t ctx; - gpgme_data_t ciphertext; - char *outfile; + int err; + gpgme_ctx_t ctx; + gpgme_data_t ciphertext; + char *outfile; - ctx = create_gpgme_context (use_smime); - if (!use_smime) - gpgme_set_armor (ctx, 1); + ctx = create_gpgme_context (use_smime); + if (!use_smime) + gpgme_set_armor (ctx, 1); - ciphertext = create_gpgme_data (); + ciphertext = create_gpgme_data (); - if (combined_signed) { - if (set_signer (ctx, use_smime)) { - gpgme_data_release (ciphertext); - gpgme_release (ctx); - return NULL; + if (combined_signed) { + if (set_signer(ctx, use_smime)) { + gpgme_data_release(ciphertext); + gpgme_release(ctx); + return NULL; + } + err = gpgme_op_encrypt_sign(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, + plaintext, ciphertext); + } else { + err = gpgme_op_encrypt(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, + plaintext, ciphertext); } - err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, - plaintext, ciphertext); - } - else - err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, - plaintext, ciphertext); - mutt_need_hard_redraw (); - if (err) { - mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err)); - gpgme_data_release (ciphertext); - gpgme_release (ctx); - return NULL; - } - gpgme_release (ctx); + mutt_need_hard_redraw(); + if (err) { + mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err)); + gpgme_data_release (ciphertext); + gpgme_release (ctx); + return NULL; + } - outfile = data_object_to_tempfile (ciphertext, NULL); - gpgme_data_release (ciphertext); - return outfile; + gpgme_release(ctx); + + outfile = data_object_to_tempfile(ciphertext, NULL); + gpgme_data_release(ciphertext); + return outfile; } /* Find the "micalg" parameter from the last Gpgme operation on @@ -682,38 +557,35 @@ static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset, which must have been allocated by the caller with size BUFLEN. Returns 0 on success or -1 in case of an error. The return string is truncted to BUFLEN - 1. */ -static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen) +static int get_micalg(gpgme_ctx_t ctx, char *buf, ssize_t buflen) { - gpgme_sign_result_t result = NULL; - const char *algorithm_name = NULL; - - if (!buflen) - return -1; + gpgme_sign_result_t result = NULL; + const char *algorithm_name = NULL; - *buf = 0; - result = gpgme_op_sign_result (ctx); - if (result) { - algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo); - if (algorithm_name) { - m_strcpy(buf, buflen, algorithm_name); + *buf = '\0'; + result = gpgme_op_sign_result(ctx); + if (result) { + algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo); + if (algorithm_name) { + m_strcpy(buf, buflen, algorithm_name); + } } - } - return *buf ? 0 : -1; + return *buf ? 0 : -1; } -static void print_time (time_t t, STATE * s) +static void print_time(time_t t, STATE *s) { - char p[STRING]; + char p[STRING]; - setlocale (LC_TIME, ""); + setlocale(LC_TIME, ""); #ifdef HAVE_LANGINFO_D_T_FMT - strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t)); + strftime(p, sizeof(p), nl_langinfo(D_T_FMT), localtime(&t)); #else - strftime (p, sizeof (p), "%c", localtime (&t)); + strftime(p, sizeof(p), "%c", localtime(&t)); #endif - setlocale (LC_TIME, "C"); - state_attach_puts (p, s); + setlocale(LC_TIME, "C"); + state_attach_puts(p, s); } /* Implementation of `sign_message'. */ @@ -721,7 +593,7 @@ static void print_time (time_t t, STATE * s) /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when USE_SMIME is passed as true. Returns the new body or NULL on error. */ -static BODY *sign_message (BODY * a, int use_smime) +static BODY *sign_message(BODY * a, int use_smime) { BODY *t; char *sigfile; @@ -732,7 +604,7 @@ static BODY *sign_message (BODY * a, int use_smime) convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */ - message = body_to_data_object (a, 1); + message = body_to_data_object(a, 1); if (!message) return NULL; signature = create_gpgme_data (); @@ -757,7 +629,7 @@ static BODY *sign_message (BODY * a, int use_smime) return NULL; } - sigfile = data_object_to_tempfile (signature, NULL); + sigfile = data_object_to_tempfile(signature, NULL); gpgme_data_release (signature); if (!sigfile) { gpgme_release (ctx); @@ -809,10 +681,6 @@ static BODY *sign_message (BODY * a, int use_smime) return a; } -/* - * Implementation of `encrypt_message'. - */ - /* Encrypt the mail body A to all keys given as space separated keyids or fingerprints in KEYLIST and return the encrypted body. */ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign) @@ -822,13 +690,13 @@ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign) gpgme_key_t *rset = NULL; gpgme_data_t plaintext; - rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP); + rset = create_recipient_set(keylist, 0); if (!rset) return NULL; if (sign) convert_to_7bit (a); - plaintext = body_to_data_object (a, 0); + plaintext = body_to_data_object(a, 0); if (!plaintext) { p_delete(&rset); return NULL; @@ -863,16 +731,11 @@ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign) t->parts->next->use_disp = 1; t->parts->next->disposition = DISPINLINE; t->parts->next->unlink = 1; /* delete after sending the message */ - t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime - can save */ + t->parts->next->d_filename = m_strdup("msg.asc"); return t; } -/* - * Implementation of `smime_build_smime_entity'. - */ - /* Encrypt the mail body A to all keys given as space separated fingerprints in KEYLIST and return the S/MIME encrypted body. */ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist) @@ -882,11 +745,11 @@ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist) gpgme_key_t *rset = NULL; gpgme_data_t plaintext; - rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS); + rset = create_recipient_set(keylist, 1); if (!rset) return NULL; - plaintext = body_to_data_object (a, 0); + plaintext = body_to_data_object(a, 0); if (!plaintext) { p_delete(&rset); return NULL; @@ -915,9 +778,6 @@ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist) return t; } - -/* Implementation of `verify_one'. */ - /* Display the common attributes of the signature summary SUM. Return 1 if there is is a severe warning. */ @@ -1127,7 +987,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s) return -1; /* Signature not found. */ if (signature_key) { - gpgme_key_release (signature_key); + gpgme_key_unref(signature_key); signature_key = NULL; } @@ -1207,7 +1067,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s) } if (key != signature_key) - gpgme_key_release (key); + gpgme_key_unref(key); } return anybad ? 1 : anywarn ? 2 : 0; @@ -1259,7 +1119,7 @@ static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime) int anybad = 0; if (signature_key) { - gpgme_key_release (signature_key); + gpgme_key_unref(signature_key); signature_key = NULL; } @@ -1312,18 +1172,14 @@ static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime) return badsig ? 1 : anywarn ? 2 : 0; } -/* - * Implementation of `decrypt_part'. - */ - /* Decrypt a PGP or SMIME message (depending on the boolean flag IS_SMIME) with body A described further by state S. Write plaintext out to file FPOUT and return a new body. For PGP returns a flag in R_IS_SIGNED to indicate whether this is a combined encrypted and signed message, for S/MIME it returns true when it is not a encrypted but a signed message. */ -static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime, - int *r_is_signed) +static BODY * +decrypt_part(BODY *a, STATE *s, FILE *fpout, int is_smime, int *r_is_signed) { struct stat info; BODY *tattach; @@ -1452,48 +1308,39 @@ restart: /* Decrypt a PGP/MIME message in FPIN and B and return a new body and the stream in CUR and FPOUT. Returns 0 on success. */ -int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur) +int crypt_pgp_decrypt_mime (FILE * fpin, FILE **fpout, BODY *b, BODY **cur) { - char tempfile[_POSIX_PATH_MAX]; - STATE s; - BODY *first_part = b; - int is_signed; + STATE s; + BODY *first_part = b; + int is_signed; - first_part->goodsig = 0; - first_part->warnsig = 0; + first_part->goodsig = 0; + first_part->warnsig = 0; - if (!mutt_is_multipart_encrypted (b)) - return -1; - - if (!b->parts || !b->parts->next) - return -1; - - b = b->parts->next; + if (!mutt_is_multipart_encrypted(b) || !b->parts || !b->parts->next) + return -1; - p_clear(&s, 1); - s.fpin = fpin; - *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); - if (!*fpout) { - mutt_perror (_("Can't create temporary file")); - return -1; - } - unlink (tempfile); + b = b->parts->next; - *cur = decrypt_part (b, &s, *fpout, 0, &is_signed); - rewind (*fpout); - if (is_signed > 0) - first_part->goodsig = 1; + p_clear(&s, 1); + s.fpin = fpin; + *fpout = tmpfile(); + if (!*fpout) { + mutt_perror (_("Can't create temporary file")); + return -1; + } - return *cur ? 0 : -1; + *cur = decrypt_part(b, &s, *fpout, 0, &is_signed); + rewind(*fpout); + first_part->goodsig = is_signed > 0; + return *cur ? 0 : -1; } /* Decrypt a S/MIME message in FPIN and B and return a new body and the stream in CUR and FPOUT. Returns 0 on success. */ -int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, - BODY ** cur) +int crypt_smime_decrypt_mime(FILE *fpin, FILE **fpout, BODY *b, BODY **cur) { - char tempfile[_POSIX_PATH_MAX]; STATE s; FILE *tmpfp = NULL; int is_signed; @@ -1517,12 +1364,11 @@ int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, p_clear(&s, 1); s.fpin = fpin; fseeko (s.fpin, b->offset, 0); - tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); + tmpfp = tmpfile(); if (!tmpfp) { mutt_perror (_("Can't create temporary file")); return -1; } - mutt_unlink (tempfile); s.fpout = tmpfp; mutt_decode_attachment (b, &s); @@ -1534,12 +1380,11 @@ int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, p_clear(&s, 1); s.fpin = tmpfp; s.fpout = 0; - *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); + *fpout = tmpfile(); if (!*fpout) { mutt_perror (_("Can't create temporary file")); return -1; } - mutt_unlink (tempfile); *cur = decrypt_part (b, &s, *fpout, 1, &is_signed); if (*cur) @@ -1569,12 +1414,11 @@ int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, p_clear(&s, 1); s.fpin = *fpout; fseeko (s.fpin, bb->offset, 0); - tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); + tmpfp = tmpfile(); if (!tmpfp) { mutt_perror (_("Can't create temporary file")); return -1; } - mutt_unlink (tempfile); s.fpout = tmpfp; mutt_decode_attachment (bb, &s); @@ -1587,12 +1431,11 @@ int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, p_clear(&s, 1); s.fpin = tmpfp; s.fpout = 0; - *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); + *fpout = tmpfile(); if (!*fpout) { mutt_perror (_("Can't create temporary file")); return -1; } - mutt_unlink (tempfile); tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed); if (tmp_b) @@ -1609,12 +1452,8 @@ int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, } -/* - * Implementation of `pgp_check_traditional'. - */ - -static int pgp_check_traditional_one_body (FILE * fp, BODY * b, - int tagged_only) +static int +pgp_check_traditional_one_body(FILE *fp, BODY *b, int tagged_only) { char tempfile[_POSIX_PATH_MAX]; char buf[HUGE_STRING]; @@ -1663,26 +1502,25 @@ static int pgp_check_traditional_one_body (FILE * fp, BODY * b, return 1; } -int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only) +int crypt_pgp_check_traditional(FILE *fp, BODY *b, int tagged_only) { - int rv = 0; - int r; + int rv = 0; - for (; b; b = b->next) { - if (is_multipart (b)) - rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv); - else if (b->type == TYPETEXT) { - if ((r = mutt_is_application_pgp (b))) - rv = (rv || r); - else - rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv); + for (; b; b = b->next) { + if (is_multipart(b)) + rv |= crypt_pgp_check_traditional(fp, b->parts, tagged_only); + if (b->type == TYPETEXT) { + int r; + if ((r = mutt_is_application_pgp(b))) { + rv |= r; + } else { + rv |= pgp_check_traditional_one_body(fp, b, tagged_only); + } + } } - } - return rv; -} - -/* Implementation of `application_handler'. */ + return rv; +} /* Copy a clearsigned message, and strip the signature and PGP's @@ -1695,8 +1533,7 @@ int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only) (Note that we aren't worse than Outlook & Cie in this, and also note that we can successfully handle anything produced by any existing versions of mutt.) */ - -static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset) +static void copy_clearsigned(gpgme_data_t data, STATE * s, char *charset) { char buf[HUGE_STRING]; short complete, armor_header; @@ -1704,7 +1541,7 @@ static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset) char *fname; FILE *fp; - fname = data_object_to_tempfile (data, &fp); + fname = data_object_to_tempfile(data, &fp); if (!fname) return; unlink (fname); @@ -1743,9 +1580,8 @@ static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset) m_fclose(&fp); } - /* Support for classic_application/pgp */ -int crypt_pgp_application_pgp_handler (BODY * m, STATE * s) +int crypt_pgp_application_pgp_handler(BODY *m, STATE *s) { int needpass = -1, pgp_keyblock = 0; int clearsign = 0; @@ -1790,8 +1626,7 @@ int crypt_pgp_application_pgp_handler (BODY * m, STATE * s) clearsign = 1; needpass = 0; } - else if (!option (OPTDONTHANDLEPGPKEYS) && - !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) { + else if (!m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) { needpass = 0; pgp_keyblock = 1; } @@ -1892,7 +1727,7 @@ int crypt_pgp_application_pgp_handler (BODY * m, STATE * s) "information --]\n\n"), s); } - tmpfname = data_object_to_tempfile (plaintext, &pgpout); + tmpfname = data_object_to_tempfile(plaintext, &pgpout); if (!tmpfname) { pgpout = NULL; state_attach_puts (_("Error: copy data failed\n"), s); @@ -1969,8 +1804,6 @@ int crypt_pgp_application_pgp_handler (BODY * m, STATE * s) return (err); } -/* Implementation of `encrypted_handler'. */ - /* MIME handler for pgp/mime encrypted messages. */ int crypt_pgp_encrypted_handler (BODY * a, STATE * s) { @@ -2133,7 +1966,7 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op, { char fmt[16]; crypt_entry_t *entry; - crypt_key_t *key; + cryptkey_t *key; int kflags = 0; int optional = (flags & M_FORMAT_OPTIONAL); const char *s = NULL; @@ -2319,10 +2152,10 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op, /* Used by the display fucntion to format a line. */ static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num) { - crypt_key_t **key_table = (crypt_key_t **) menu->data; + cryptkey_t **cryptkey_table = (cryptkey_t **) menu->data; crypt_entry_t entry; - entry.key = key_table[num]; + entry.key = cryptkey_table[num]; entry.num = num + 1; m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry, @@ -2332,8 +2165,8 @@ static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num) /* Compare two addresses and the keyid to be used for sorting. */ static int _crypt_compare_address (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; int r; if ((r = m_strcasecmp((*s)->uid, (*t)->uid))) @@ -2352,8 +2185,8 @@ static int crypt_compare_address (const void *a, const void *b) /* Compare two key IDs and the addresses to be used for sorting. */ static int _crypt_compare_keyid (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; int r; if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)))) @@ -2371,8 +2204,8 @@ static int crypt_compare_keyid (const void *a, const void *b) /* Compare 2 creation dates and the addresses. For sorting. */ static int _crypt_compare_date (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; unsigned long ts = 0, tt = 0; if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0)) @@ -2398,8 +2231,8 @@ static int crypt_compare_date (const void *a, const void *b) addresses and the key IDs. For sorting. */ static int _crypt_compare_trust (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; unsigned long ts = 0, tt = 0; int r; @@ -2629,7 +2462,7 @@ failure: displayed in a proper way, which does mean to reorder some parts for S/MIME's DNs. USERID is a string as returned by the gpgme key functions. It is utf-8 encoded. */ -static void parse_and_print_user_id (FILE * fp, const char *userid) +static void parse_and_print_user_id(FILE * fp, const char *userid) { const char *s; int i; @@ -2641,7 +2474,7 @@ static void parse_and_print_user_id (FILE * fp, const char *userid) } else if (*userid == '(') fputs (_("[Can't display this user ID (unknown encoding)]"), fp); - else if (!digit_or_letter ((const unsigned char *) userid)) + else if (*userid & ~127 || __m_strdigits[(int)*userid] == 255) fputs (_("[Can't display this user ID (invalid encoding)]"), fp); else { struct dn_array_s *dn = parse_dn ((const unsigned char *) userid); @@ -2660,12 +2493,12 @@ static void parse_and_print_user_id (FILE * fp, const char *userid) } typedef enum { - KEY_CAP_CAN_ENCRYPT, - KEY_CAP_CAN_SIGN, - KEY_CAP_CAN_CERTIFY + KEY_CAP_CAN_ENCRYPT, + KEY_CAP_CAN_SIGN, + KEY_CAP_CAN_CERTIFY } key_cap_t; -static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap) +static unsigned int key_check_cap(gpgme_key_t key, key_cap_t cap) { gpgme_subkey_t subkey = NULL; unsigned int ret = 0; @@ -2916,7 +2749,7 @@ static void print_key_info (gpgme_key_t key, FILE * fp) /* Show detailed information about the selected key */ -static void verify_key (crypt_key_t * key) +static void verify_key (cryptkey_t * key) { FILE *fp; char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; @@ -2949,7 +2782,7 @@ static void verify_key (crypt_key_t * key) while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) { putc ('\n', fp); err = gpgme_op_keylist_start (listctx, s, 0); - gpgme_key_release (k); + gpgme_key_unref(k); k = NULL; if (!err) err = gpgme_op_keylist_next (listctx, &k); @@ -2968,221 +2801,132 @@ static void verify_key (crypt_key_t * key) } leave: - gpgme_key_release (k); + gpgme_key_unref(k); gpgme_release (listctx); m_fclose(&fp); mutt_clear_error (); snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key)); - mutt_do_pager (cmd, tempfile, 0, NULL); + mutt_pager(cmd, tempfile, 0, NULL); } /* Implementation of `findkeys'. */ -/* Convert string_list_t into a pattern string suitable to be passed to GPGME. - We need to convert spaces in an item into a '+' and '%' into - "%25". */ -static char *list_to_pattern (string_list_t * list) +static void add_hints(string_array *arr, const char *s) { - string_list_t *l; - char *pattern, *p; - const char *s; - ssize_t n; + if (!s) + return; - n = 0; - for (l = list; l; l = l->next) { - for (s = l->data; *s; s++) { - if (*s == '%') - n += 2; - n++; + while (*s) { + int l = strcspn(s, " ,.:\"()<>\n"); + string_array_append(arr, p_dupstr(s, l)); + s += l; + s += strspn(s, " ,.:\"()<>\n"); } - n++; /* delimiter or end of string */ - } - n++; /* make sure to allocate at least one byte */ - pattern = p = p_new(char, n); - for (l = list; l; l = l->next) { - s = l->data; - if (*s) { - if (l != list) - *p++ = ' '; - for (s = l->data; *s; s++) { - if (*s == '%') { - *p++ = '%'; - *p++ = '2'; - *p++ = '5'; - } - else if (*s == '+') { - *p++ = '%'; - *p++ = '2'; - *p++ = 'B'; - } - else if (*s == ' ') - *p++ = '+'; - else - *p++ = *s; - } - } - } - *p = 0; - return pattern; } -/* Return a list of keys which are candidates for the selection. - Select by looking at the HINTS list. */ -static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app, - int secret) +/* Return a list of keys which are candidates for the selection. */ +static cryptkey_t * +get_candidates(string_array *hints, unsigned int app, int secret) { - crypt_key_t *db, *k, **kend; - char *pattern; - gpgme_error_t err; - gpgme_ctx_t ctx; - gpgme_key_t key; - int idx; - gpgme_user_id_t uid = NULL; - - pattern = list_to_pattern (hints); - if (!pattern) - return NULL; - - err = gpgme_new (&ctx); - if (err) { - mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err)); - p_delete(&pattern); - return NULL; - } - - db = NULL; - kend = &db; - - if ((app & APPLICATION_PGP)) { - /* Its all a mess. That old GPGME expects different things - depending on the protocol. For gpg we don' t need percent - escaped pappert but simple strings passed in an array to the - keylist_ext_start function. */ - string_list_t *l; - ssize_t n; - char **patarr; + cryptkey_t *res = NULL, **kend = &res; + gpgme_error_t err; + gpgme_ctx_t ctx; + gpgme_key_t key; - for (l = hints, n = 0; l; l = l->next) { - if (l->data && *l->data) - n++; - } - if (!n) - goto no_pgphints; + if (hints->len <= 0) + return NULL; + string_array_append(hints, NULL); + ctx = create_gpgme_context(0); - patarr = p_new(char *, n + 1); - for (l = hints, n = 0; l; l = l->next) { - if (l->data && *l->data) - patarr[n++] = m_strdup(l->data); - } - patarr[n] = NULL; - err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0); - for (n = 0; patarr[n]; n++) - p_delete(&patarr[n]); - p_delete(&patarr); - if (err) { - mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err)); - gpgme_release (ctx); - p_delete(&pattern); - return NULL; - } + if ((app & APPLICATION_PGP)) { + err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr, + secret, 0); + if (err) { + mutt_error(_("gpgme_op_keylist_start failed: %s"), + gpgme_strerror(err)); + gpgme_release(ctx); + return NULL; + } - while (!(err = gpgme_op_keylist_next (ctx, &key))) { - unsigned int flags = 0; - - if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) - flags |= KEYFLAG_CANENCRYPT; - if (key_check_cap (key, KEY_CAP_CAN_SIGN)) - flags |= KEYFLAG_CANSIGN; - - for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { - k = p_new(crypt_key_t, 1); - k->kobj = key; - k->idx = idx; - k->uid = uid->uid; - k->flags = flags; - *kend = k; - kend = &k->next; - } + while (!(err = gpgme_op_keylist_next(ctx, &key))) { + gpgme_user_id_t uid = NULL; + unsigned int flags = 0; + int idx; + + if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT)) + flags |= KEYFLAG_CANENCRYPT; + if (key_check_cap(key, KEY_CAP_CAN_SIGN)) + flags |= KEYFLAG_CANSIGN; + + for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { + cryptkey_t *k = p_new(cryptkey_t, 1); + k->kobj = key; + k->idx = idx; + k->uid = uid->uid; + k->flags = flags; + *kend = k; + kend = &k->next; + } + } + if (gpg_err_code(err) != GPG_ERR_EOF) + mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err)); + gpgme_op_keylist_end(ctx); } - if (gpg_err_code (err) != GPG_ERR_EOF) - mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err)); - gpgme_op_keylist_end (ctx); - no_pgphints: - ; - } - if ((app & APPLICATION_SMIME)) { - /* and now look for x509 certificates */ - gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS); - err = gpgme_op_keylist_start (ctx, pattern, 0); - if (err) { - mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err)); - gpgme_release (ctx); - p_delete(&pattern); - return NULL; - } + if ((app & APPLICATION_SMIME)) { + gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS); + err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr, + secret, 0); + if (err) { + mutt_error(_("gpgme_op_keylist_start failed: %s"), + gpgme_strerror(err)); + gpgme_release(ctx); + return NULL; + } - while (!(err = gpgme_op_keylist_next (ctx, &key))) { - unsigned int flags = KEYFLAG_ISX509; - - if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) - flags |= KEYFLAG_CANENCRYPT; - if (key_check_cap (key, KEY_CAP_CAN_SIGN)) - flags |= KEYFLAG_CANSIGN; - - for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { - k = p_new(crypt_key_t, 1); - k->kobj = key; - k->idx = idx; - k->uid = uid->uid; - k->flags = flags; - *kend = k; - kend = &k->next; - } + while (!(err = gpgme_op_keylist_next(ctx, &key))) { + gpgme_user_id_t uid = NULL; + unsigned int flags = KEYFLAG_ISX509; + int idx; + + if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT)) + flags |= KEYFLAG_CANENCRYPT; + if (key_check_cap(key, KEY_CAP_CAN_SIGN)) + flags |= KEYFLAG_CANSIGN; + + for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { + cryptkey_t *k = p_new(cryptkey_t, 1); + k->kobj = key; + k->idx = idx; + k->uid = uid->uid; + k->flags = flags; + *kend = k; + kend = &k->next; + } + } + if (gpg_err_code(err) != GPG_ERR_EOF) + mutt_error(_("gpgme_op_keylist_next failed: %s"), + gpgme_strerror(err)); + gpgme_op_keylist_end(ctx); } - if (gpg_err_code (err) != GPG_ERR_EOF) - mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err)); - gpgme_op_keylist_end (ctx); - } - - gpgme_release (ctx); - p_delete(&pattern); - return db; -} - -/* Add the string STR to the list HINTS. This list is later used to - match addresses. */ -static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str) -{ - char *scratch; - char *t; - - if ((scratch = m_strdup(str)) == NULL) - return hints; - for (t = strtok (scratch, " ,.:\"()<>\n"); t; - t = strtok (NULL, " ,.:\"()<>\n")) { - if (m_strlen(t) > 3) - hints = mutt_add_list(hints, t); - } - - p_delete(&scratch); - return hints; + gpgme_release(ctx); + return res; } /* Display a menu to select a key from the array KEYS. FORCED_VALID will be set to true on return if the user did override the the key's validity. */ -static crypt_key_t *crypt_select_key (crypt_key_t * keys, +static cryptkey_t *crypt_select_key (cryptkey_t * keys, address_t * p, const char *s, unsigned int app, int *forced_valid) { int keymax; - crypt_key_t **key_table; + cryptkey_t **cryptkey_table; MUTTMENU *menu; int i, done = 0; char helpstr[STRING], buf[LONG_STRING]; - crypt_key_t *k; + cryptkey_t *k; int (*f) (const void *, const void *); int menu_to_use = 0; int unusable = 0; @@ -3191,49 +2935,49 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, /* build the key table */ keymax = i = 0; - key_table = NULL; + cryptkey_table = NULL; for (k = keys; k; k = k->next) { - if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) { - unusable = 1; - continue; - } + if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) { + unusable = 1; + continue; + } - if (i == keymax) { - keymax += 20; - p_realloc(&key_table, keymax); - } + if (i == keymax) { + keymax += 20; + p_realloc(&cryptkey_table, keymax); + } - key_table[i++] = k; + cryptkey_table[i++] = k; } if (!i && unusable) { - mutt_error _("All matching keys are marked expired/revoked."); + mutt_error _("All matching keys are marked expired/revoked."); - mutt_sleep (1); - return NULL; + mutt_sleep (1); + return NULL; } switch (PgpSortKeys & SORT_MASK) { - case SORT_DATE: - f = crypt_compare_date; - break; - case SORT_KEYID: - f = crypt_compare_keyid; - break; - case SORT_ADDRESS: - f = crypt_compare_address; - break; - case SORT_TRUST: - default: - f = crypt_compare_trust; - break; + case SORT_DATE: + f = crypt_compare_date; + break; + case SORT_KEYID: + f = crypt_compare_keyid; + break; + case SORT_ADDRESS: + f = crypt_compare_address; + break; + case SORT_TRUST: + default: + f = crypt_compare_trust; + break; } - qsort (key_table, i, sizeof (crypt_key_t *), f); + qsort (cryptkey_table, i, sizeof (cryptkey_t *), f); if (app & APPLICATION_PGP) - menu_to_use = MENU_KEY_SELECT_PGP; + menu_to_use = MENU_KEY_SELECT_PGP; else if (app & APPLICATION_SMIME) - menu_to_use = MENU_KEY_SELECT_SMIME; + menu_to_use = MENU_KEY_SELECT_SMIME; helpstr[0] = 0; mutt_make_help (buf, sizeof (buf), _("Exit "), menu_to_use, OP_EXIT); @@ -3252,594 +2996,536 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, menu->make_entry = crypt_entry; menu->menu = menu_to_use; menu->help = helpstr; - menu->data = key_table; + menu->data = cryptkey_table; { - const char *ts; - - if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME)) - ts = _("PGP and S/MIME keys matching"); - else if ((app & APPLICATION_PGP)) - ts = _("PGP keys matching"); - else if ((app & APPLICATION_SMIME)) - ts = _("S/MIME keys matching"); - else - ts = _("keys matching"); + const char *ts; + + if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME)) + ts = _("PGP and S/MIME keys matching"); + else if ((app & APPLICATION_PGP)) + ts = _("PGP keys matching"); + else if ((app & APPLICATION_SMIME)) + ts = _("S/MIME keys matching"); + else + ts = _("keys matching"); - if (p) - snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox); - else - snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s); - menu->title = buf; + if (p) + snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox); + else + snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s); + menu->title = buf; } mutt_clear_error (); k = NULL; while (!done) { - *forced_valid = 0; - switch (mutt_menuLoop (menu)) { - case OP_VERIFY_KEY: - verify_key (key_table[menu->current]); - menu->redraw = REDRAW_FULL; - break; - - case OP_VIEW_ID: - mutt_message ("%s", key_table[menu->current]->uid); - break; - - case OP_GENERIC_SELECT_ENTRY: - /* FIXME make error reporting more verbose - this should be - easy because gpgme provides more information */ - if (option (OPTPGPCHECKTRUST)) { - if (!crypt_key_is_valid (key_table[menu->current])) { - mutt_error _("This key can't be used: " - "expired/disabled/revoked."); + *forced_valid = 0; + switch (mutt_menuLoop (menu)) { + case OP_VERIFY_KEY: + verify_key (cryptkey_table[menu->current]); + menu->redraw = REDRAW_FULL; break; - } - } - if (option (OPTPGPCHECKTRUST) && - (!crypt_id_is_valid (key_table[menu->current]) - || !crypt_id_is_strong (key_table[menu->current]))) { - const char *warn_s; - char buff[LONG_STRING]; + case OP_VIEW_ID: + mutt_message ("%s", cryptkey_table[menu->current]->uid); + break; - if (key_table[menu->current]->flags & KEYFLAG_CANTUSE) - s = N_("ID is expired/disabled/revoked."); - else { - gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN; - gpgme_user_id_t uid = NULL; - int j = 0; - - warn_s = "??"; - - uid = key_table[menu->current]->kobj->uids; - for (j = 0; (j < key_table[menu->current]->idx) && uid; - j++, uid = uid->next); - if (uid) - val = uid->validity; - - switch (val) { - case GPGME_VALIDITY_UNKNOWN: - case GPGME_VALIDITY_UNDEFINED: - warn_s = N_("ID has undefined validity."); - break; - case GPGME_VALIDITY_NEVER: - warn_s = N_("ID is not valid."); - break; - case GPGME_VALIDITY_MARGINAL: - warn_s = N_("ID is only marginally valid."); - break; - case GPGME_VALIDITY_FULL: - case GPGME_VALIDITY_ULTIMATE: - break; + case OP_GENERIC_SELECT_ENTRY: + /* FIXME make error reporting more verbose - this should be + easy because gpgme provides more information */ + if (option (OPTPGPCHECKTRUST)) { + if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE ) { + mutt_error(_("This key can't be used: " + "expired/disabled/revoked.")); + break; + } } - snprintf (buff, sizeof (buff), - _("%s Do you really want to use the key?"), _(warn_s)); - - if (mutt_yesorno (buff, 0) != 1) { - mutt_clear_error (); - break; + if (option (OPTPGPCHECKTRUST) && + ((cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE) + || !crypt_id_is_strong (cryptkey_table[menu->current]))) { + const char *warn_s; + char buff[LONG_STRING]; + + if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE) + s = N_("ID is expired/disabled/revoked."); + else { + gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN; + gpgme_user_id_t uid = NULL; + int j = 0; + + warn_s = "??"; + + uid = cryptkey_table[menu->current]->kobj->uids; + for (j = 0; (j < cryptkey_table[menu->current]->idx) && uid; + j++, uid = uid->next); + if (uid) + val = uid->validity; + + switch (val) { + case GPGME_VALIDITY_UNKNOWN: + case GPGME_VALIDITY_UNDEFINED: + warn_s = N_("ID has undefined validity."); + break; + case GPGME_VALIDITY_NEVER: + warn_s = N_("ID is not valid."); + break; + case GPGME_VALIDITY_MARGINAL: + warn_s = N_("ID is only marginally valid."); + break; + case GPGME_VALIDITY_FULL: + case GPGME_VALIDITY_ULTIMATE: + break; + } + + snprintf (buff, sizeof (buff), + _("%s Do you really want to use the key?"), _(warn_s)); + + if (mutt_yesorno (buff, 0) != 1) { + mutt_clear_error (); + break; + } + *forced_valid = 1; + } } - *forced_valid = 1; - } - } - k = crypt_copy_key (key_table[menu->current]); - done = 1; - break; + k = cryptkey_dup(cryptkey_table[menu->current]); + done = 1; + break; - case OP_EXIT: - k = NULL; - done = 1; - break; - } + case OP_EXIT: + k = NULL; + done = 1; + break; + } } mutt_menuDestroy (&menu); - p_delete(&key_table); + p_delete(&cryptkey_table); set_option (OPTNEEDREDRAW); return k; } -static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities, - unsigned int app, int *forced_valid) +static cryptkey_t * +crypt_getkeybyaddr(address_t * a, int abilities, int app, int *forced_valid) { - address_t *r, *p; - string_list_t *hints = NULL; - - int weak = 0; - int invalid = 0; - int multi = 0; - int this_key_has_strong; - int this_key_has_weak; - int this_key_has_invalid; - int match; + address_t *r, *p; - crypt_key_t *keys, *k; - crypt_key_t *the_valid_key = NULL; - crypt_key_t *matches = NULL; - crypt_key_t **matches_endp = &matches; - - *forced_valid = 0; + int weak = 0; + int invalid = 0; + int multi = 0; + int this_key_has_strong; + int this_key_has_weak; + int this_key_has_invalid; + int match; - if (a && a->mailbox) - hints = crypt_add_string_to_hints (hints, a->mailbox); - if (a && a->personal) - hints = crypt_add_string_to_hints (hints, a->personal); + cryptkey_t *keys, *k; + cryptkey_t *the_valid_key = NULL; + cryptkey_t *matches = NULL; + cryptkey_t **matches_endp = &matches; - mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); - keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN)); - - string_list_wipe(&hints); + *forced_valid = 0; - if (!keys) - return NULL; + { + string_array hints; + string_array_init(&hints); + add_hints(&hints, a->mailbox); + add_hints(&hints, a->personal); - for (k = keys; k; k = k->next) { - if (abilities && !(k->flags & abilities)) { - continue; + mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); + keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN)); + string_array_wipe(&hints); } - this_key_has_weak = 0; /* weak but valid match */ - this_key_has_invalid = 0; /* invalid match */ - this_key_has_strong = 0; /* strong and valid match */ - match = 0; /* any match */ - - r = rfc822_parse_adrlist (NULL, k->uid); - for (p = r; p; p = p->next) { - int validity = crypt_id_matches_addr (a, p, k); - - if (validity & CRYPT_KV_MATCH) /* something matches */ - match = 1; - - /* is this key a strong candidate? */ - if ((validity & CRYPT_KV_VALID) - && (validity & CRYPT_KV_STRONGID) - && (validity & CRYPT_KV_ADDR)) { - if (the_valid_key && the_valid_key != k) - multi = 1; - the_valid_key = k; - this_key_has_strong = 1; - } - else if ((validity & CRYPT_KV_MATCH) - && !(validity & CRYPT_KV_VALID)) - this_key_has_invalid = 1; - else if ((validity & CRYPT_KV_MATCH) - && (!(validity & CRYPT_KV_STRONGID) - || !(validity & CRYPT_KV_ADDR))) - this_key_has_weak = 1; - } - address_list_wipe(&r); + if (!keys) + return NULL; - if (match) { - crypt_key_t *tmp; + for (k = keys; k; k = k->next) { + if (abilities && !(k->flags & abilities)) { + continue; + } - if (!this_key_has_strong && this_key_has_invalid) - invalid = 1; - if (!this_key_has_strong && this_key_has_weak) - weak = 1; + this_key_has_weak = 0; /* weak but valid match */ + this_key_has_invalid = 0; /* invalid match */ + this_key_has_strong = 0; /* strong and valid match */ + match = 0; /* any match */ + + r = rfc822_parse_adrlist (NULL, k->uid); + for (p = r; p; p = p->next) { + int validity = crypt_id_matches_addr (a, p, k); + + if (validity & CRYPT_KV_MATCH) /* something matches */ + match = 1; + + /* is this key a strong candidate? */ + if ((validity & CRYPT_KV_VALID) + && (validity & CRYPT_KV_STRONGID) + && (validity & CRYPT_KV_ADDR)) { + if (the_valid_key && the_valid_key != k) + multi = 1; + the_valid_key = k; + this_key_has_strong = 1; + } + else if ((validity & CRYPT_KV_MATCH) + && !(validity & CRYPT_KV_VALID)) + this_key_has_invalid = 1; + else if ((validity & CRYPT_KV_MATCH) + && (!(validity & CRYPT_KV_STRONGID) + || !(validity & CRYPT_KV_ADDR))) + this_key_has_weak = 1; + } + address_list_wipe(&r); - *matches_endp = tmp = crypt_copy_key (k); - matches_endp = &tmp->next; - the_valid_key = tmp; - } - } + if (match) { + cryptkey_t *tmp; - crypt_free_key (&keys); + if (!this_key_has_strong && this_key_has_invalid) + invalid = 1; + if (!this_key_has_strong && this_key_has_weak) + weak = 1; - if (matches) { - if (the_valid_key && !multi && !weak - && !(invalid && option (OPTPGPSHOWUNUSABLE))) { - /* - * There was precisely one strong match on a valid ID, there - * were no valid keys with weak matches, and we aren't - * interested in seeing invalid keys. - * - * Proceed without asking the user. - */ - k = crypt_copy_key (the_valid_key); + *matches_endp = tmp = cryptkey_dup(k); + matches_endp = &tmp->next; + the_valid_key = tmp; + } } - else { - /* - * Else: Ask the user. - */ - k = crypt_select_key (matches, a, NULL, app, forced_valid); + key_list_wipe(&keys); + + if (matches) { + if (the_valid_key && !multi && !weak + && !(invalid && option (OPTPGPSHOWUNUSABLE))) { + /* + * There was precisely one strong match on a valid ID, there + * were no valid keys with weak matches, and we aren't + * interested in seeing invalid keys. + * + * Proceed without asking the user. + */ + k = cryptkey_dup(the_valid_key); + } else { + /* + * Else: Ask the user. + */ + k = crypt_select_key (matches, a, NULL, app, forced_valid); + } + key_list_wipe(&matches); + } else { + k = NULL; } - crypt_free_key (&matches); - } - else - k = NULL; - return k; + return k; } -static crypt_key_t *crypt_getkeybystr (const char *p, short abilities, - unsigned int app, int *forced_valid) +static cryptkey_t * +crypt_getkeybystr(const char *p, int abilities, int app, int *forced_valid) { - string_list_t *hints = NULL; - crypt_key_t *keys; - crypt_key_t *matches = NULL; - crypt_key_t **matches_endp = &matches; - crypt_key_t *k; + cryptkey_t *keys; + cryptkey_t *matches = NULL; + cryptkey_t **matches_endp = &matches; + cryptkey_t *k; int match; mutt_message (_("Looking for keys matching \"%s\"..."), p); *forced_valid = 0; - hints = crypt_add_string_to_hints (hints, p); - keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN)); - string_list_wipe(&hints); + { + string_array hints; + string_array_init(&hints); + add_hints(&hints, p); + keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN)); + string_array_wipe(&hints); + } if (!keys) return NULL; for (k = keys; k; k = k->next) { + const char *s = crypt_keyid(k); + if (abilities && !(k->flags & abilities)) continue; match = 0; - if (!*p || !m_strcasecmp(p, crypt_keyid (k)) - || (!m_strncasecmp(p, "0x", 2) - && !m_strcasecmp(p + 2, crypt_keyid (k))) - || (option (OPTPGPLONGIDS) - && !m_strncasecmp(p, "0x", 2) - && !m_strcasecmp(p + 2, crypt_keyid (k) + 8)) - || m_stristr(k->uid, p)) { - crypt_key_t *tmp; + if (!*p || !m_strcasecmp(p, s) + || (!m_strncasecmp(p, "0x", 2) && !m_strcasecmp(p + 2, s)) + || m_stristr(k->uid, p)) + { + cryptkey_t *tmp; - *matches_endp = tmp = crypt_copy_key (k); + *matches_endp = tmp = cryptkey_dup(k); matches_endp = &tmp->next; } } - - crypt_free_key (&keys); + key_list_wipe(&keys); if (matches) { k = crypt_select_key (matches, NULL, p, app, forced_valid); - crypt_free_key (&matches); + key_list_wipe(&matches); return k; } return NULL; } -/* Display TAG as a prompt to ask for a key. If WHATFOR is not null - use it as default and store it under that label as the next - default. ABILITIES describe the required key abilities (sign, - encrypt) and APP the type of the requested key; ether S/MIME or - PGP. Return a copy of the key or NULL if not found. */ -static crypt_key_t *crypt_ask_for_key (char *tag, - char *whatfor, - short abilities, - unsigned int app, int *forced_valid) +/* Display TAG as a prompt to ask for a key. + * ABILITIES describe the required key abilities (sign, encrypt) and APP the + * type of the requested key; ether S/MIME or PGP. + * Return a copy of the key or NULL if not found. */ +static cryptkey_t * +crypt_ask_for_key(const char *tag, int abilities, int app, int *forced_valid) { - crypt_key_t *key; - char resp[STRING]; - struct crypt_cache *l = NULL; - int dummy; - - if (!forced_valid) - forced_valid = &dummy; - - mutt_clear_error (); + cryptkey_t *key; + char resp[STRING]; + int dummy; - *forced_valid = 0; - resp[0] = 0; - if (whatfor) { + if (!forced_valid) + forced_valid = &dummy; + *forced_valid = 0; - for (l = id_defaults; l; l = l->next) - if (!m_strcasecmp(whatfor, l->what)) { - m_strcpy(resp, sizeof(resp), NONULL(l->dflt)); - break; - } - } + mutt_clear_error(); + for (;;) { + resp[0] = 0; + if (mutt_get_field(tag, resp, sizeof(resp), M_CLEAR) != 0) + return NULL; + if (m_strisempty(resp)) + return NULL; - for (;;) { - resp[0] = 0; - if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0) - return NULL; + if ((key = crypt_getkeybystr(resp, abilities, app, forced_valid))) + return key; - if (whatfor) { - if (l) - m_strreplace(&l->dflt, resp); - else { - l = p_new(struct crypt_cache, 1); - l->next = id_defaults; - id_defaults = l; - l->what = m_strdup(whatfor); - l->dflt = m_strdup(resp); - } + BEEP (); } - - if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid))) - return key; - - BEEP (); - } - /* not reached */ } /* This routine attempts to find the keyids of the recipients of a message. It returns NULL if any of the keys can not be found. */ -static char *find_keys (address_t * to, address_t * cc, address_t * bcc, - unsigned int app) +static char *find_keys(ENVELOPE *env, unsigned int app) { - char *keylist = NULL, *t; - const char *keyID; - ssize_t keylist_size = 0; - ssize_t keylist_used = 0; - address_t *tmp = NULL, *addr = NULL; - address_t **last = &tmp; - address_t *p, *q; - int i; - crypt_key_t *k_info, *key; - const char *fqdn = mutt_fqdn (1); - -#if 0 - *r_application = APPLICATION_PGP | APPLICATION_SMIME; -#endif - - for (i = 0; i < 3; i++) { - switch (i) { - case 0: - p = to; - break; - case 1: - p = cc; - break; - case 2: - p = bcc; - break; - default: - abort (); - } - - *last = address_list_dup (p); - while (*last) - last = &((*last)->next); - } - - rfc822_qualify(tmp, fqdn); - address_list_uniq(tmp); + address_t *lst = NULL, *addr; + buffer_t *keylist = buffer_new(); - for (p = tmp; p; p = p->next) { - char buf[LONG_STRING]; - int forced_valid = 0; - - q = p; - k_info = NULL; + { + address_t **last = &lst; + *last = address_list_dup(env->to); + last = address_list_last(last); + *last = address_list_dup(env->cc); + last = address_list_last(last); + *last = address_list_dup(env->bcc); + + rfc822_qualify(lst, mutt_fqdn(1)); + address_list_uniq(lst); + } + + while ((addr = address_list_pop(&lst))) { + char buf[STRING]; + int forced_valid = 0; + const char *keyID; + cryptkey_t *key = NULL; + + if ((keyID = mutt_crypt_hook(addr))) { + int r; + + snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyID, + addr->mailbox); + r = mutt_yesorno(buf, M_YES); + + if (r == -1) { + address_list_wipe(&lst); + address_list_wipe(&addr); + buffer_delete(&keylist); + return NULL; + } - if ((keyID = mutt_crypt_hook (p)) != NULL) { - int r; + if (r == M_YES) { + address_t *a; + /* check for e-mail address */ + if (strchr(keyID, '@') && (a = rfc822_parse_adrlist(NULL, keyID))) { + rfc822_qualify(a, mutt_fqdn(1)); + address_list_wipe(&addr); + addr = a; + } else { + key = crypt_getkeybystr(keyID, KEYFLAG_CANENCRYPT, app, + &forced_valid); + } + } + } - snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), - keyID, p->mailbox); - if ((r = mutt_yesorno (buf, M_YES)) == M_YES) { - /* check for e-mail address */ - if ((t = strchr (keyID, '@')) && - (addr = rfc822_parse_adrlist (NULL, keyID))) { - rfc822_qualify(addr, fqdn); - q = addr; + if (!key) { + key = crypt_getkeybyaddr(addr, KEYFLAG_CANENCRYPT, app, &forced_valid); } - else { - k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT, - app, &forced_valid); + if (!key) { + snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), addr->mailbox); + key = crypt_ask_for_key(buf, KEYFLAG_CANENCRYPT, app, + &forced_valid); + if (!key) { + address_list_wipe(&lst); + address_list_wipe(&addr); + buffer_delete(&keylist); + return NULL; + } } - } - else if (r == -1) { - p_delete(&keylist); - address_list_wipe(&tmp); - address_list_wipe(&addr); - return NULL; - } - } - if (k_info == NULL - && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT, - app, &forced_valid)) == NULL) { - snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox); + if (keylist->len) + buffer_addch(keylist, ' '); + buffer_addstr(keylist, "0x"); + buffer_addstr(keylist, crypt_fpr(key)); + if (forced_valid) + buffer_addch(keylist, '!'); - if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT, - app, - &forced_valid)) == NULL) { - p_delete(&keylist); - address_list_wipe(&tmp); + key_list_wipe(&key); address_list_wipe(&addr); - return NULL; - } - } - else - key = k_info; - - { - const char *s = crypt_fpr (key); - - keylist_size += m_strlen(s) + 4 + 1; - p_realloc(&keylist, keylist_size); - sprintf (keylist + keylist_used, "%s0x%s%s", - keylist_used ? " " : "", s, forced_valid ? "!" : ""); } - keylist_used = m_strlen(keylist); - crypt_free_key (&key); - address_list_wipe(&addr); - } - address_list_wipe(&tmp); - return (keylist); + address_list_wipe(&lst); + return buffer_unwrap(&keylist); } -int crypt_get_keys (HEADER * msg, char **keylist) +int crypt_get_keys(HEADER *msg, char **keylist) { - /* Do a quick check to make sure that we can find all of the encryption - * keys if the user has requested this service. - */ + /* Do a quick check to make sure that we can find all of the encryption + * keys if the user has requested this service. + */ - *keylist = NULL; + *keylist = NULL; - if (msg->security & ENCRYPT) { - if (msg->security & APPLICATION_PGP) { - set_option(OPTPGPCHECKTRUST); - *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc, - APPLICATION_PGP); - unset_option(OPTPGPCHECKTRUST); - if (!*keylist) - return -1; - } + if (msg->security & ENCRYPT) { + if (msg->security & APPLICATION_PGP) { + set_option(OPTPGPCHECKTRUST); + *keylist = find_keys(msg->env, APPLICATION_PGP); + unset_option(OPTPGPCHECKTRUST); + if (!*keylist) + return -1; + } - if (msg->security & APPLICATION_SMIME) { - *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc, - APPLICATION_SMIME); - if (!*keylist) - return -1; + if (msg->security & APPLICATION_SMIME) { + *keylist = find_keys(msg->env, APPLICATION_SMIME); + if (!*keylist) + return -1; + } } - } - return (0); + return 0; } int crypt_send_menu (HEADER * msg, int *redraw, int is_smime) { - crypt_key_t *p; - char input_signas[STRING]; - int choice; + cryptkey_t *p; + char buf[STRING]; + int choice; + + if (msg->security & APPLICATION_SMIME) + is_smime = 1; + if (msg->security & APPLICATION_PGP) + is_smime = 0; + + choice = is_smime + ? mutt_multi_choice(_("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"), + _("esabpc")) + : mutt_multi_choice(_("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"), + _("esabmc")); + + switch (choice) { + case 1: /* (e)ncrypt */ + msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT); + msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN); + break; - if (msg->security & APPLICATION_PGP) - is_smime = 0; - else if (msg->security & APPLICATION_SMIME) - is_smime = 1; + case 2: /* (s)ign */ + msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); + msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT); + break; - if (is_smime) - choice = - mutt_multi_choice (_ - ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"), - _("esabpc")); - else - choice = - mutt_multi_choice (_ - ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"), - _("esabmc")); - - switch (choice) { - case 1: /* (e)ncrypt */ - msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT); - msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN); - break; + case 3: /* sign (a)s */ + p = crypt_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN, + is_smime ? APPLICATION_SMIME : APPLICATION_PGP, + NULL); + if (p) { + snprintf(buf, sizeof(buf), "0x%s", crypt_keyid(p)); + m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, buf); + key_list_wipe(&p); + msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); + } + *redraw = REDRAW_FULL; + break; - case 2: /* (s)ign */ - msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); - msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT); - break; + case 4: /* (b)oth */ + if (is_smime) { + msg->security = SMIMEENCRYPT | SMIMESIGN; + } else { + msg->security = PGPENCRYPT | PGPSIGN; + } + break; - case 3: /* sign (a)s */ - if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN, - is_smime ? APPLICATION_SMIME : - APPLICATION_PGP, NULL))) { - snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p)); - m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, - input_signas); - crypt_free_key (&p); + case 5: /* (p)gp or s/(m)ime */ + is_smime = !is_smime; + break; - msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); + case 6: /* (c)lear */ + return msg->security = 0; } - *redraw = REDRAW_FULL; - break; - - case 4: /* (b)oth */ - msg->security = - (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN)); - break; - - case 5: /* (p)gp or s/(m)ime */ - is_smime = !is_smime; - break; - - case 6: /* (c)lear */ - return msg->security = 0; - } - if (is_smime) { - msg->security &= ~APPLICATION_PGP; - msg->security |= APPLICATION_SMIME; - } else { - msg->security &= ~APPLICATION_SMIME; - msg->security |= APPLICATION_PGP; - } + if (is_smime) { + msg->security &= ~APPLICATION_PGP; + msg->security |= APPLICATION_SMIME; + } else { + msg->security &= ~APPLICATION_SMIME; + msg->security |= APPLICATION_PGP; + } - return msg->security; + return msg->security; } -int crypt_smime_verify_sender (HEADER * h) +int crypt_smime_verify_sender(HEADER *h) { - address_t *sender = NULL; - unsigned int ret = 1; + address_t *sender = NULL; + unsigned int ret = 1; - if (h->env->from) { - h->env->from = mutt_expand_aliases (h->env->from); - sender = h->env->from; - } - else if (h->env->sender) { - h->env->sender = mutt_expand_aliases (h->env->sender); - sender = h->env->sender; - } + if (h->env->from) { + h->env->from = mutt_expand_aliases(h->env->from); + sender = h->env->from; + } else if (h->env->sender) { + h->env->sender = mutt_expand_aliases (h->env->sender); + sender = h->env->sender; + } - if (sender) { - if (signature_key) { - gpgme_key_t key = signature_key; - gpgme_user_id_t uid = NULL; - int sender_length = 0; - int uid_length = 0; - - sender_length = m_strlen(sender->mailbox); - for (uid = key->uids; uid && ret; uid = uid->next) { - uid_length = m_strlen(uid->email); - if (1 && (uid->email[0] == '<') - && (uid->email[uid_length - 1] == '>') - && (uid_length == sender_length + 2) - && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length))) - ret = 0; - } + if (!sender) { + mutt_any_key_to_continue ("Failed to figure out sender"); + goto end; } - else - mutt_any_key_to_continue ("Failed to verify sender"); - } - else - mutt_any_key_to_continue ("Failed to figure out sender"); - if (signature_key) { - gpgme_key_release (signature_key); - signature_key = NULL; - } + if (signature_key) { + gpgme_key_t key = signature_key; + gpgme_user_id_t uid = NULL; + int sender_length = 0; + int uid_length = 0; + + sender_length = m_strlen(sender->mailbox); + for (uid = key->uids; uid && ret; uid = uid->next) { + uid_length = m_strlen(uid->email); + if (1 && (uid->email[0] == '<') + && (uid->email[uid_length - 1] == '>') + && (uid_length == sender_length + 2) + && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length))) + ret = 0; + } + } else { + mutt_any_key_to_continue ("Failed to verify sender"); + } - return ret; + end: + if (signature_key) { + gpgme_key_unref(signature_key); + signature_key = NULL; + } + return ret; } static void crypt_invoke_import(FILE *stream, int smime) @@ -3890,43 +3576,17 @@ static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top) void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top) { - mutt_endwin (NULL); - set_option (OPTDONTHANDLEPGPKEYS); - - for (; top; top = top->next) { - if (!tag || top->tagged) - pgp_extract_keys_from_attachment (fp, top); - - if (!tag) - break; - } - - unset_option (OPTDONTHANDLEPGPKEYS); -} - - -/* TODO */ - -/* fixme: needs documentation. */ -void crypt_pgp_invoke_getkeys (address_t * addr) -{ -} - -/* Generate a PGP public key attachment. */ -BODY *crypt_pgp_make_key_attachment (char *tempf) -{ - return NULL; -} + mutt_endwin (NULL); -/* S/MIME */ + for (; top; top = top->next) { + if (!tag || top->tagged) + pgp_extract_keys_from_attachment (fp, top); -/* fixme: Needs documentation. */ -void crypt_smime_getkeys (ENVELOPE * env) -{ + if (!tag) + break; + } } -/***************************************************************************/ - void crypt_invoke_message (int type) { if (type & APPLICATION_PGP) { @@ -4138,7 +3798,6 @@ void crypt_extract_keys_from_messages(HEADER * h) return; } - set_option(OPTDONTHANDLEPGPKEYS); if (!h) { int i; for (i = 0; i < Context->vcount; i++) { @@ -4149,35 +3808,27 @@ void crypt_extract_keys_from_messages(HEADER * h) } else { extract_keys_aux(tmpfp, h); } - unset_option(OPTDONTHANDLEPGPKEYS); m_fclose(&tmpfp); if (isendwin()) mutt_any_key_to_continue(NULL); } - - -static void crypt_fetch_signatures (BODY ***signatures, BODY * a, int *n) +static void crypt_fetch_signatures(BODY ***signatures, BODY * a, int *n) { - for (; a; a = a->next) { - if (a->type == TYPEMULTIPART) - crypt_fetch_signatures (signatures, a->parts, n); - else { - if ((*n % 5) == 0) - p_realloc(signatures, *n + 6); + for (; a; a = a->next) { + if (a->type == TYPEMULTIPART) { + crypt_fetch_signatures(signatures, a->parts, n); + } else { + if ((*n % 5) == 0) + p_realloc(signatures, *n + 6); - (*signatures)[(*n)++] = a; + (*signatures)[(*n)++] = a; + } } - } } - -/* - * This routine verifies a "multipart/signed" body. - */ - -int mutt_signed_handler (BODY * a, STATE * s) +int mutt_signed_handler(BODY *a, STATE *s) { unsigned major, minor; char *protocol;