📄 smime.c
字号:
/* * Copyright (C) 2001,2002 Oliver Ehli <elmy@acm.org> * Copyright (C) 2002 Mike Schiraldi <raldi@research.netsol.com> * Copyright (C) 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#include "mutt.h"#include "mutt_curses.h"#include "mutt_menu.h"#include "smime.h"#include "mime.h"#include "copy.h"#include <sys/wait.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <sys/stat.h>#include <errno.h>#include <ctype.h>#ifdef HAVE_LOCALE_H#include <locale.h>#endif#ifdef HAVE_SYS_TIME_H# include <sys/time.h>#endif#ifdef HAVE_SYS_RESOURCE_H# include <sys/resource.h>#endif#ifdef CRYPT_BACKEND_CLASSIC_SMIME#include "mutt_crypt.h"struct smime_command_context { const char *key; /* %k */ const char *cryptalg; /* %a */ const char *fname; /* %f */ const char *sig_fname; /* %s */ const char *certificates; /* %c */ const char *intermediates; /* %i */};typedef struct { unsigned int hash; char suffix; char email[256]; char nick[256]; char trust; /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */ short public; /* 1=public 0=private */} smime_id;char SmimePass[STRING];time_t SmimeExptime = 0; /* when does the cached passphrase expire? */static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 };static char SmimeCertToUse[_POSIX_PATH_MAX];static char SmimeIntermediateToUse[_POSIX_PATH_MAX];/* * Queries and passphrase handling. *//* these are copies from pgp.c */void smime_void_passphrase (void){ memset (SmimePass, 0, sizeof (SmimePass)); SmimeExptime = 0;}int smime_valid_passphrase (void){ time_t now = time (NULL); if (now < SmimeExptime) /* Use cached copy. */ return 1; smime_void_passphrase(); if (mutt_get_password (_("Enter S/MIME passphrase:"), SmimePass, sizeof (SmimePass)) == 0) { SmimeExptime = time (NULL) + SmimeTimeout; return (1); } else SmimeExptime = 0; return 0;}/* * The OpenSSL interface *//* This is almost identical to ppgp's invoking interface. */static const char *_mutt_fmt_smime_command (char *dest, size_t destlen, char op, const char *src, const char *prefix, const char *ifstring, const char *elsestring, unsigned long data, format_flag flags){ char fmt[16]; struct smime_command_context *cctx = (struct smime_command_context *) data; int optional = (flags & M_FORMAT_OPTIONAL); switch (op) { case 'C': { if (!optional) { char path[_POSIX_PATH_MAX]; char buf1[LONG_STRING], buf2[LONG_STRING]; struct stat sb; strfcpy (path, NONULL (SmimeCALocation), sizeof (path)); mutt_expand_path (path, sizeof (path)); mutt_quote_filename (buf1, sizeof (buf1), path); if (stat (path, &sb) != 0 || !S_ISDIR (sb.st_mode)) snprintf (buf2, sizeof (buf2), "-CAfile %s", buf1); else snprintf (buf2, sizeof (buf2), "-CApath %s", buf1); snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, buf2); } else if (!SmimeCALocation) optional = 0; break; } case 'c': { /* certificate (list) */ if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL(cctx->certificates)); } else if (!cctx->certificates) optional = 0; break; } case 'i': { /* intermediate certificates */ if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL(cctx->intermediates)); } else if (!cctx->intermediates) optional = 0; break; } case 's': { /* detached signature */ if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname)); } else if (!cctx->sig_fname) optional = 0; break; } case 'k': { /* private key */ if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->key)); } else if (!cctx->key) optional = 0; break; } case 'a': { /* algorithm for encryption */ if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->cryptalg)); } else if (!cctx->key) optional = 0; break; } case 'f': { /* file to process */ if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->fname)); } else if (!cctx->fname) optional = 0; break; } default: *dest = '\0'; break; } if (optional) mutt_FormatString (dest, destlen, ifstring, _mutt_fmt_smime_command, data, 0); else if (flags & M_FORMAT_OPTIONAL) mutt_FormatString (dest, destlen, elsestring, _mutt_fmt_smime_command, data, 0); return (src);}static void mutt_smime_command (char *d, size_t dlen, struct smime_command_context *cctx, const char *fmt){ mutt_FormatString (d, dlen, NONULL(fmt), _mutt_fmt_smime_command, (unsigned long) cctx, 0); dprint (2,(debugfile, "mutt_smime_command: %s\n", d));}static pid_t smime_invoke (FILE **smimein, FILE **smimeout, FILE **smimeerr, int smimeinfd, int smimeoutfd, int smimeerrfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *key, const char *certificates, const char *intermediates, const char *format){ struct smime_command_context cctx; char cmd[HUGE_STRING]; memset (&cctx, 0, sizeof (cctx)); if (!format || !*format) return (pid_t) -1; cctx.fname = fname; cctx.sig_fname = sig_fname; cctx.key = key; cctx.cryptalg = cryptalg; cctx.certificates = certificates; cctx.intermediates = intermediates; mutt_smime_command (cmd, sizeof (cmd), &cctx, format); return mutt_create_filter_fd (cmd, smimein, smimeout, smimeerr, smimeinfd, smimeoutfd, smimeerrfd);}/* * Key and certificate handling. *//* Search the certificate index for given mailbox. return certificate file name.*/static void smime_entry (char *s, size_t l, MUTTMENU * menu, int num){ smime_id *Table = (smime_id*) menu->data; smime_id this = Table[num]; char* truststate; switch(this.trust) { case 't': truststate = N_("Trusted "); break; case 'v': truststate = N_("Verified "); break; case 'u': truststate = N_("Unverified"); break; case 'e': truststate = N_("Expired "); break; case 'r': truststate = N_("Revoked "); break; case 'i': truststate = N_("Invalid "); break; default: truststate = N_("Unknown "); } if (this.public) snprintf(s, l, " 0x%.8X.%i %s %-35.35s %s", this.hash, this.suffix, truststate, this.email, this.nick); else snprintf(s, l, " 0x%.8X.%i %-35.35s %s", this.hash, this.suffix, this.email, this.nick);}char* smime_ask_for_key (char *prompt, char *mailbox, short public){ char *fname; smime_id *Table; long cert_num; /* Will contain the number of certificates. * To be able to get it, the .index file will be read twice... */ char index_file[_POSIX_PATH_MAX]; FILE *index; char buf[LONG_STRING]; char fields[5][STRING]; int numFields, hash_suffix, done, cur; /* The current entry */ MUTTMENU* menu; unsigned int hash; char helpstr[HUGE_STRING*3]; char qry[256]; char title[256]; if (!prompt) prompt = _("Enter keyID: "); snprintf(index_file, sizeof (index_file), "%s/.index", public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys)); index = fopen(index_file, "r"); if (index == NULL) { mutt_perror (index_file); return NULL; } /* Count Lines */ cert_num = 0; while (!feof(index)) { if (fgets(buf, sizeof(buf), index)) cert_num++; } fclose(index); FOREVER { *qry = 0; if (mutt_get_field(prompt, qry, sizeof(qry), 0)) return NULL; snprintf(title, sizeof(title), _("S/MIME certificates matching \"%s\"."), qry); index = fopen(index_file, "r"); if (index == NULL) { mutt_perror (index_file); return NULL; } /* Read Entries */ cur = 0; Table = safe_calloc(cert_num, sizeof (smime_id)); while (!feof(index)) { numFields = fscanf (index, MUTT_FORMAT(STRING) " %x.%i " MUTT_FORMAT(STRING), fields[0], &hash, &hash_suffix, fields[2]); if (public) fscanf (index, MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) "\n", fields[3], fields[4]); /* 0=email 1=name 2=nick 3=intermediate 4=trust */ if (numFields < 2) continue; /* Check if query matches this certificate */ if (!mutt_stristr(fields[0], qry) && !mutt_stristr(fields[2], qry)) continue; Table[cur].hash = hash; Table[cur].suffix = hash_suffix; strncpy(Table[cur].email, fields[0], sizeof(Table[cur].email)); strncpy(Table[cur].nick, fields[2], sizeof(Table[cur].nick)); Table[cur].trust = *fields[4]; Table[cur].public = public; cur++; } fclose(index); /* Make Helpstring */ helpstr[0] = 0; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_SMIME, OP_EXIT); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Select "), MENU_SMIME, OP_GENERIC_SELECT_ENTRY); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof(buf), _("Help"), MENU_SMIME, OP_HELP); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ /* Create the menu */ menu = mutt_new_menu(); menu->max = cur; menu->make_entry = smime_entry; menu->menu = MENU_SMIME; menu->help = helpstr; menu->data = Table; menu->title = title; /* sorting keys might be done later - TODO */ mutt_clear_error(); done = 0; hash = 0; while (!done) { switch (mutt_menuLoop (menu)) { case OP_GENERIC_SELECT_ENTRY: cur = menu->current; hash = 1; done = 1; break; case OP_EXIT: hash = 0; done = 1; break; } } if (hash) { fname = safe_malloc(13); /* Hash + '.' + Suffix + \0 */ sprintf(fname, "%.8x.%i", Table[cur].hash, Table[cur].suffix); } else fname = NULL; mutt_menuDestroy (&menu); FREE (&Table); set_option (OPTNEEDREDRAW); if (fname) return fname; }}char *smime_get_field_from_db (char *mailbox, char *query, short public, short may_ask){ int addr_len, query_len, found = 0, ask = 0, choice = 0; char cert_path[_POSIX_PATH_MAX]; char buf[LONG_STRING], prompt[STRING]; char fields[5][STRING]; char key[STRING]; int numFields; struct stat info; char key_trust_level = 0; FILE *fp; if(!mailbox && !query) return(NULL); addr_len = mailbox ? mutt_strlen (mailbox) : 0; query_len = query ? mutt_strlen (query) : 0; *key = '\0'; /* index-file format: mailbox certfile label issuer_certfile trust_flags\n certfile is a hash value generated by openssl. Note that this was done according to the OpenSSL specs on their CA-directory. */ snprintf (cert_path, sizeof (cert_path), "%s/.index", (public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys))); if (!stat (cert_path, &info)) { if ((fp = safe_fopen (cert_path, "r")) == NULL) { mutt_perror (cert_path); return (NULL); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -