⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 crypt-gpgme.c

📁 mutt-1.5.12 源代码。linux 下邮件接受的工具。
💻 C
📖 第 1 页 / 共 5 页
字号:
/* crypt-gpgme.c - GPGME based crypto operations * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu> * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de> * Copyright (C) 2001  Thomas Roessler <roessler@guug.de> *                     Oliver Ehli <elmy@acm.org> * Copyright (C) 2002, 2003, 2004 g10 Code GmbH * *     This program is free software; you can redistribute it and/or modify *     it under the terms of the GNU General Public License as published by *     the Free Software Foundation; either version 2 of the License, or *     (at your option) any later version. *  *     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, write to the Free Software *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. */#if HAVE_CONFIG_H# include "config.h"#endif#ifdef CRYPT_BACKEND_GPGME#include "mutt.h"#include "mutt_crypt.h"#include "mutt_menu.h"#include "mutt_curses.h"#include "mime.h"#include "copy.h"#include "pager.h"#include "sort.h"#include <sys/wait.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <sys/stat.h>#include <errno.h>#include <ctype.h>#include <gpgme.h>#ifdef HAVE_LOCALE_H#include <locale.h>#endif#ifdef HAVE_LANGINFO_D_T_FMT#include <langinfo.h>#endif#ifdef HAVE_SYS_TIME_H# include <sys/time.h>#endif#ifdef HAVE_SYS_RESOURCE_H# include <sys/resource.h>#endif/* * Helper macros. */#define digitp(p)   (*(p) >= '0' && *(p) <= '9')#define hexdigitp(a) (digitp (a)                     \                      || (*(a) >= 'A' && *(a) <= 'F')  \                      || (*(a) >= 'a' && *(a) <= 'f'))#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))/* Values used for comparing addresses. */#define CRYPT_KV_VALID    1#define CRYPT_KV_ADDR     2#define CRYPT_KV_STRING   4#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;};/* 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 crypt_entry{  size_t num;  crypt_key_t *key;} crypt_entry_t;static struct crypt_cache *id_defaults = NULL;static gpgme_key_t signature_key = NULL;/* * General helper functions. *//* return true when S pints to a didgit or letter. */static intdigit_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 voidprint_utf8 (FILE *fp, const char *buf, size_t len){  char *tstr;  tstr = safe_malloc (len+1);  memcpy (tstr, buf, len);  tstr[len] = 0;  mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);  fputs (tstr, fp);  FREE (&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){  const char *s = "????????";  if (k->kobj && k->kobj->subkeys)    {      s = k->kobj->subkeys->keyid;      if ((! option (OPTPGPLONGIDS)) && (strlen (s) == 16))	/* Return only the short keyID.  */	s += 8;    }  return s;}/* Return the hexstring fingerprint from the key K. */static const char *crypt_fpr (crypt_key_t *k){  const char *s = "";  if (k->kobj && k->kobj->subkeys)    s = k->kobj->subkeys->fpr;  return s;}/* Parse FLAGS and return a statically allocated(!) string with them. */static char *crypt_key_abilities (int flags){  static char buff[3];  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';  buff[2] = '\0';  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     return ' ';}/* Return a copy of KEY. */static crypt_key_t *crypt_copy_key (crypt_key_t *key){  crypt_key_t *k;  k = safe_calloc (1, sizeof *k);  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;      FREE (&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){  gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;  gpgme_user_id_t uid = NULL;  unsigned int is_strong = 0;  unsigned 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;    case GPGME_VALIDITY_FULL:    case GPGME_VALIDITY_ULTIMATE:      is_strong = 1;      break;    }  return is_strong;}/* 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 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 *addr, ADDRESS *u_addr,                                  crypt_key_t *key){  int rv = 0;    if (crypt_id_is_valid (key))    rv |= CRYPT_KV_VALID;  if (crypt_id_is_strong (key))    rv |= CRYPT_KV_STRONGID;    if (addr->mailbox && u_addr->mailbox      && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)    rv |= CRYPT_KV_ADDR;      if (addr->personal && u_addr->personal      && mutt_strcasecmp (addr->personal, u_addr->personal) == 0)    rv |= CRYPT_KV_STRING;    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){  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);    }  if (for_smime)    {      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){  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;}/* 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){  char tempfile[_POSIX_PATH_MAX];  FILE *fptmp;  int err = 0;  gpgme_data_t data;    mutt_mktemp (tempfile);  fptmp = safe_fopen (tempfile, "w+");  if (!fptmp)    {      mutt_perror (tempfile);      return NULL;    }  mutt_write_mime_header (a, fptmp);  fputc ('\n', fptmp);  mutt_write_mime_body (a, fptmp);  if (convert)    {      int c, hadcr = 0;      unsigned char buf[1];      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);                }                                hadcr = 0;            }          /* FIXME: This is quite suboptimal */          buf[0] = c;          gpgme_data_write (data, buf, 1);        }      fclose(fptmp);      gpgme_data_seek (data, 0, SEEK_SET);    }  else    {      fclose(fptmp);      err = gpgme_data_new_from_file (&data, tempfile, 1);    }  unlink (tempfile);  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){  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;    }  return data;}/* Write a GPGME data object to the stream 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;    }  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;}/* 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){  int err;  char tempfile[_POSIX_PATH_MAX];  FILE *fp;  size_t nread = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -