/** * crypt_invoke_message - Display an informative message * @param type Crypto type, see #SecurityFlags * * Show a message that a backend will be invoked. */ void crypt_invoke_message(SecurityFlags type) { if (((WithCrypto & APPLICATION_PGP) != 0) && (type & APPLICATION_PGP)) mutt_message(_("Invoking PGP...")); else if (((WithCrypto & APPLICATION_SMIME) != 0) && (type & APPLICATION_SMIME)) mutt_message(_("Invoking S/MIME...")); }
/* Show a message that a backend will be invoked. */ void crypt_invoke_message(int type) { if ((WithCrypto & APPLICATION_PGP) && (type & APPLICATION_PGP)) mutt_message("Invoking PGP..."); else if ((WithCrypto & APPLICATION_SMIME) && (type & APPLICATION_SMIME)) mutt_message("Invoking S/MIME..."); }
/* imap_auth_login: Plain LOGIN support */ imap_auth_res_t imap_auth_login (IMAP_DATA* idata, const char* method) { char q_user[SHORT_STRING], q_pass[SHORT_STRING]; char buf[STRING]; int rc; if (bit_val(idata->capabilities, LOGINDISABLED)) { mutt_message("LOGIN disabled on this server."); return IMAP_AUTH_UNAVAIL; } if (mutt_account_getuser (&idata->conn->account)) return IMAP_AUTH_FAILURE; if (mutt_account_getpass (&idata->conn->account)) return IMAP_AUTH_FAILURE; mutt_message("Logging in..."); imap_quote_string (q_user, sizeof (q_user), idata->conn->account.user); imap_quote_string (q_pass, sizeof (q_pass), idata->conn->account.pass); snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass); rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK | IMAP_CMD_PASS); if (!rc) { mutt_clear_error(); /* clear "Logging in...". fixes #3524 */ return IMAP_AUTH_SUCCESS; } mutt_error("Login failed."); mutt_sleep (2); return IMAP_AUTH_FAILURE; }
/** * execute_command - Run a system command * @param m Mailbox to work with * @param command Command string to execute * @param progress Message to show the user * @retval 1 Success * @retval 0 Failure * * Run the supplied command, taking care of all the NeoMutt requirements, * such as locking files and blocking signals. */ static int execute_command(struct Mailbox *m, const char *command, const char *progress) { int rc = 1; char sys_cmd[STR_COMMAND]; if (!m || !command || !progress) return 0; if (!m->quiet) { mutt_message(progress, m->realpath); } mutt_sig_block(); endwin(); fflush(stdout); expand_command_str(m, command, sys_cmd, sizeof(sys_cmd)); if (mutt_system(sys_cmd) != 0) { rc = 0; mutt_any_key_to_continue(NULL); mutt_error(_("Error running \"%s\""), sys_cmd); } mutt_sig_unblock(); return rc; }
static int add_entropy (const char *file) { struct stat st; int n = -1; if (!file) return 0; if (stat (file, &st) == -1) return errno == ENOENT ? 0 : -1; mutt_message (_("Filling entropy pool: %s...\n"), file); /* check that the file permissions are secure */ if (st.st_uid != getuid () || ((st.st_mode & (S_IWGRP | S_IRGRP)) != 0) || ((st.st_mode & (S_IWOTH | S_IROTH)) != 0)) { mutt_error (_("%s has insecure permissions!"), file); mutt_sleep (2); return -1; } #ifdef HAVE_RAND_EGD n = RAND_egd (file); #endif if (n <= 0) n = RAND_load_file (file, -1); #ifndef HAVE_RAND_STATUS if (n > 0) entropy_byte_count += n; #endif return n; }
/* enter a mutt command */ void mutt_enter_command (void) { BUFFER err, token; char buffer[LONG_STRING]; int r; buffer[0] = 0; if (mutt_get_field (":", buffer, sizeof (buffer), M_COMMAND) != 0 || !buffer[0]) return; mutt_buffer_init (&err); err.dsize = STRING; err.data = safe_malloc(err.dsize); mutt_buffer_init (&token); r = mutt_parse_rc_line (buffer, &token, &err); FREE (&token.data); if (err.data[0]) { /* since errbuf could potentially contain printf() sequences in it, we must call mutt_error() in this fashion so that vsprintf() doesn't expect more arguments that we passed */ if (r == 0) mutt_message ("%s", err.data); else mutt_error ("%s", err.data); } FREE (&err.data); }
static QUERY *run_query (char *s, int quiet) { FILE *fp; QUERY *first = NULL; QUERY *cur = NULL; char cmd[_POSIX_PATH_MAX]; char *buf = NULL; size_t buflen; int dummy = 0; char msg[STRING]; char *p; pid_t thepid; mutt_expand_file_fmt (cmd, sizeof(cmd), QueryCmd, s); if ((thepid = mutt_create_filter (cmd, NULL, &fp, NULL)) < 0) { dprint (1, (debugfile, "unable to fork command: %s", cmd)); return 0; } if (!quiet) mutt_message _("Waiting for response..."); fgets (msg, sizeof (msg), fp); if ((p = strrchr (msg, '\n'))) *p = '\0'; while ((buf = mutt_read_line (buf, &buflen, fp, &dummy, 0)) != NULL) { if ((p = strtok(buf, "\t\n"))) { if (first == NULL) { first = (QUERY *) safe_calloc (1, sizeof (QUERY)); cur = first; } else { cur->next = (QUERY *) safe_calloc (1, sizeof (QUERY)); cur = cur->next; } cur->addr = rfc822_parse_adrlist (cur->addr, p); p = strtok(NULL, "\t\n"); if (p) { cur->name = safe_strdup (p); p = strtok(NULL, "\t\n"); if (p) cur->other = safe_strdup (p); } } } FREE (&buf); safe_fclose (&fp); if (mutt_wait_filter (thepid)) { dprint (1, (debugfile, "Error: %s\n", msg)); if (!quiet) mutt_error ("%s", msg); } else { if (!quiet) mutt_message ("%s", msg); } return first; }
/** * mutt_progress_init - Set up a progress bar * @param progress Progress bar * @param msg Message to display * @param flags Flags, e.g. #MUTT_PROGRESS_SIZE * @param inc Increments to display (0 disables updates) * @param size Total size of expected file / traffic */ void mutt_progress_init(struct Progress *progress, const char *msg, unsigned short flags, unsigned short inc, size_t size) { struct timeval tv = { 0, 0 }; if (!progress) return; if (OptNoCurses) return; memset(progress, 0, sizeof(struct Progress)); progress->inc = inc; progress->flags = flags; progress->msg = msg; progress->size = size; if (progress->size != 0) { if (progress->flags & MUTT_PROGRESS_SIZE) { mutt_str_pretty_size(progress->sizestr, sizeof(progress->sizestr), progress->size); } else snprintf(progress->sizestr, sizeof(progress->sizestr), "%zu", progress->size); } if (inc == 0) { if (size != 0) mutt_message("%s (%s)", msg, progress->sizestr); else mutt_message(msg); return; } if (gettimeofday(&tv, NULL) < 0) mutt_debug(LL_DEBUG1, "gettimeofday failed: %d\n", errno); /* if timestamp is 0 no time-based suppression is done */ if (C_TimeInc != 0) { progress->timestamp = ((unsigned int) tv.tv_sec * 1000) + (unsigned int) (tv.tv_usec / 1000); } mutt_progress_update(progress, 0, 0); }
/* return 0 on success, -1 on failure */ int mutt_sync_compressed (CONTEXT * ctx) { char *cmd; int rc = 0; FILE *fp; COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo; if (!ctx->quiet) mutt_message (_("Compressing %s..."), ctx->realpath); cmd = get_compression_cmd (ci->close, ctx); if (cmd == NULL) return (-1); if ((fp = fopen (ctx->realpath, "a")) == NULL) { mutt_perror (ctx->realpath); mem_free (&cmd); return (-1); } mutt_block_signals (); if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) { fclose (fp); mutt_unblock_signals (); mutt_error _("Unable to lock mailbox!"); store_size (ctx); mem_free (&cmd); return (-1); } debug_print (2, ("CompressCommand: '%s'\n", cmd)); endwin (); fflush (stdout); sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath); mutt_system (echo_cmd); if (mutt_system (cmd)) { mutt_any_key_to_continue (NULL); mutt_error (_ ("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"), ctx->path); rc = -1; } mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); mem_free (&cmd); store_size (ctx); return (rc); }
/** * imap_auth_oauth - Authenticate an IMAP connection using OAUTHBEARER * @param adata Imap Account data * @param method Name of this authentication method (UNUSED) * @retval num Result, e.g. #IMAP_AUTH_SUCCESS */ enum ImapAuthRes imap_auth_oauth(struct ImapAccountData *adata, const char *method) { char *ibuf = NULL; char *oauthbearer = NULL; int ilen; int rc; /* For now, we only support SASL_IR also and over TLS */ if (!(adata->capabilities & IMAP_CAP_AUTH_OAUTHBEARER) || !(adata->capabilities & IMAP_CAP_SASL_IR) || !adata->conn->ssf) { return IMAP_AUTH_UNAVAIL; } /* If they did not explicitly request or configure oauth then fail quietly */ if (!(method || (C_ImapOauthRefreshCommand && *C_ImapOauthRefreshCommand))) return IMAP_AUTH_UNAVAIL; mutt_message(_("Authenticating (OAUTHBEARER)...")); /* We get the access token from the imap_oauth_refresh_command */ oauthbearer = mutt_account_getoauthbearer(&adata->conn->account); if (!oauthbearer) return IMAP_AUTH_FAILURE; ilen = mutt_str_strlen(oauthbearer) + 30; ibuf = mutt_mem_malloc(ilen); snprintf(ibuf, ilen, "AUTHENTICATE OAUTHBEARER %s", oauthbearer); /* This doesn't really contain a password, but the token is good for * an hour, so suppress it anyways. */ rc = imap_exec(adata, ibuf, IMAP_CMD_PASS); FREE(&oauthbearer); FREE(&ibuf); if (rc != IMAP_EXEC_SUCCESS) { /* The error response was in SASL continuation, so continue the SASL * to cause a failure and exit SASL input. See RFC 7628 3.2.3 */ mutt_socket_send(adata->conn, "\001"); rc = imap_exec(adata, ibuf, IMAP_CMD_NO_FLAGS); } if (rc == IMAP_EXEC_SUCCESS) { mutt_clear_error(); return IMAP_AUTH_SUCCESS; } mutt_error(_("OAUTHBEARER authentication failed.")); return IMAP_AUTH_FAILURE; }
void mutt_print_message (HEADER *h) { if (quadoption (OPT_PRINT) && (!PrintCmd || !*PrintCmd)) { mutt_message (_("No printing command has been defined.")); return; } if (query_quadoption (OPT_PRINT, h ? _("Print message?") : _("Print tagged messages?")) != M_YES) return; if (_mutt_pipe_message (h, PrintCmd, option (OPTPRINTDECODE), 1, option (OPTPRINTSPLIT), "\f") == 0) mutt_message (h ? _("Message printed") : _("Messages printed")); else mutt_message (h ? _("Message could not be printed") : _("Messages could not be printed")); }
static int register_gpgme() { if (!bit_val(options, OPTCRYPTUSEGPGME)) { mutt_message(("\"crypt_use_gpgme\" set" " but not built with GPGME support.")); return 0; } else { crypto_module_register(&crypt_mod_pgp_gpgme); crypto_module_register(&crypt_mod_smime_gpgme); return 1; } }
/* ssl_negotiate: After SSL state has been initialized, attempt to negotiate * SSL over the wire, including certificate checks. */ static int ssl_negotiate (CONNECTION *conn, sslsockdata* ssldata) { int err; const char* errmsg; SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY); if ((err = SSL_connect (ssldata->ssl)) != 1) { switch (SSL_get_error (ssldata->ssl, err)) { case SSL_ERROR_SYSCALL: errmsg = _("I/O error"); break; case SSL_ERROR_SSL: errmsg = ERR_error_string (ERR_get_error (), NULL); break; default: errmsg = _("unknown error"); } mutt_error (_("SSL failed: %s"), errmsg); mutt_sleep (1); return -1; } ssldata->cert = SSL_get_peer_certificate (ssldata->ssl); if (!ssldata->cert) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (1); return -1; } if (!ssl_check_certificate (conn, ssldata)) return -1; /* L10N: %1$s is version (e.g. "TLSv1.2") %2$s is cipher_version (e.g. "TLSv1/SSLv3") %3$s is cipher_name (e.g. "ECDHE-RSA-AES128-GCM-SHA256") */ mutt_message (_("%s connection using %s (%s)"), SSL_get_version(ssldata->ssl), SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl)); mutt_sleep (0); return 0; }
/* ssl_negotiate: After SSL state has been initialised, attempt to negotiate * SSL over the wire, including certificate checks. */ static int ssl_negotiate (CONNECTION *conn, sslsockdata* ssldata) { int err; const char* errmsg; #if OPENSSL_VERSION_NUMBER >= 0x00906000L /* This only exists in 0.9.6 and above. Without it we may get interrupted * reads or writes. Bummer. */ SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY); #endif if ((err = SSL_connect (ssldata->ssl)) != 1) { switch (SSL_get_error (ssldata->ssl, err)) { case SSL_ERROR_SYSCALL: errmsg = _("I/O error"); break; case SSL_ERROR_SSL: errmsg = ERR_error_string (ERR_get_error (), NULL); break; default: errmsg = _("unknown error"); } mutt_error (_("SSL failed: %s"), errmsg); mutt_sleep (1); return -1; } ssldata->cert = SSL_get_peer_certificate (ssldata->ssl); if (!ssldata->cert) { mutt_error (_("Unable to get certificate from peer")); mutt_sleep (1); return -1; } if (!ssl_check_certificate (conn, ssldata)) return -1; mutt_message (_("%s connection using %s (%s)"), SSL_get_version(ssldata->ssl), SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl)); mutt_sleep (0); return 0; }
/** * crypt_forget_passphrase - Forget a passphrase and display a message */ void crypt_forget_passphrase(void) { if (WithCrypto & APPLICATION_PGP) crypt_pgp_void_passphrase(); if (WithCrypto & APPLICATION_SMIME) crypt_smime_void_passphrase(); if (WithCrypto) { /* L10N: Due to the implementation details (e.g. some passwords are managed by gpg-agent) we cannot know whether we forgot zero, 1, 12, ... passwords. So in English we use "Passphrases". Your language might have other means to express this. */ mutt_message(_("Passphrases forgotten")); } }
/** * crypt_init - Initialise the crypto backends * * This calls CryptModuleSpecs::init() */ void crypt_init(void) { #ifdef CRYPT_BACKEND_CLASSIC_PGP if ( #ifdef CRYPT_BACKEND_GPGME (!C_CryptUseGpgme) #else 1 #endif ) crypto_module_register(&CryptModPgpClassic); #endif #ifdef CRYPT_BACKEND_CLASSIC_SMIME if ( #ifdef CRYPT_BACKEND_GPGME (!C_CryptUseGpgme) #else 1 #endif ) crypto_module_register(&CryptModSmimeClassic); #endif if (C_CryptUseGpgme) { #ifdef CRYPT_BACKEND_GPGME crypto_module_register(&CryptModPgpGpgme); crypto_module_register(&CryptModSmimeGpgme); #else mutt_message(_("\"crypt_use_gpgme\" set" " but not built with GPGME support")); if (mutt_any_key_to_continue(NULL) == -1) mutt_exit(1); #endif } #if defined(CRYPT_BACKEND_CLASSIC_PGP) || \ defined(CRYPT_BACKEND_CLASSIC_SMIME) || defined(CRYPT_BACKEND_GPGME) if (CRYPT_MOD_CALL_CHECK(PGP, init)) CRYPT_MOD_CALL(PGP, init)(); if (CRYPT_MOD_CALL_CHECK(SMIME, init)) CRYPT_MOD_CALL(SMIME, init)(); #endif }
void crypt_init (void) { #ifdef CRYPT_BACKEND_CLASSIC_PGP if ( #ifdef CRYPT_BACKEND_GPGME (! option (OPTCRYPTUSEGPGME)) #else 1 #endif ) crypto_module_register (&crypt_mod_pgp_classic); #endif #ifdef CRYPT_BACKEND_CLASSIC_SMIME if ( #ifdef CRYPT_BACKEND_GPGME (! option (OPTCRYPTUSEGPGME)) #else 1 #endif ) crypto_module_register (&crypt_mod_smime_classic); #endif if (option (OPTCRYPTUSEGPGME)) { #ifdef CRYPT_BACKEND_GPGME crypto_module_register (&crypt_mod_pgp_gpgme); crypto_module_register (&crypt_mod_smime_gpgme); #else mutt_message (_("\"crypt_use_gpgme\" set" " but not built with GPGME support.")); if (mutt_any_key_to_continue (NULL) == -1) mutt_exit(1); #endif } #if defined CRYPT_BACKEND_CLASSIC_PGP || defined CRYPT_BACKEND_CLASSIC_SMIME || defined CRYPT_BACKEND_GPGME if (CRYPT_MOD_CALL_CHECK (PGP, init)) (CRYPT_MOD_CALL (PGP, init)) (); if (CRYPT_MOD_CALL_CHECK (SMIME, init)) (CRYPT_MOD_CALL (SMIME, init)) (); #endif }
void mutt_display_address (ENVELOPE *env) { char *pfx = NULL; char buf[SHORT_STRING]; ADDRESS *adr = NULL; adr = mutt_get_address (env, &pfx); if (!adr) return; /* * Note: We don't convert IDNA to local representation this time. * That is intentional, so the user has an opportunity to copy & * paste the on-the-wire form of the address to other, IDN-unable * software. */ buf[0] = 0; rfc822_write_address (buf, sizeof (buf), adr, 0); mutt_message ("%s: %s", pfx, buf); }
static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last, const char *subdir, const char *fname, int *count, int is_old) { struct maildir *entry; HEADER *h; char buf[_POSIX_PATH_MAX]; if(subdir) snprintf(buf, sizeof(buf), "%s/%s/%s", ctx->path, subdir, fname); else snprintf(buf, sizeof(buf), "%s/%s", ctx->path, fname); if((h = maildir_parse_message(ctx->magic, buf, is_old)) != NULL) { if(count) { (*count)++; if (!ctx->quiet && ReadInc && ((*count % ReadInc) == 0 || *count == 1)) mutt_message (_("Reading %s... %d"), ctx->path, *count); } if (subdir) { snprintf (buf, sizeof (buf), "%s/%s", subdir, fname); h->path = safe_strdup (buf); } else h->path = safe_strdup (fname); entry = safe_calloc(sizeof(struct maildir), 1); entry->h = h; **last = entry; *last = &entry->next; return 0; } return -1; }
/* imap_auth_sasl: Default authenticator if available. */ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) { sasl_conn_t* saslconn; sasl_interact_t* interaction = NULL; int rc, irc; char buf[HUGE_STRING]; const char* mech; const char *pc = NULL; unsigned int len, olen; unsigned char client_start; if (mutt_sasl_client_new (idata->conn, &saslconn) < 0) { dprint (1, (debugfile, "imap_auth_sasl: Error allocating SASL connection.\n")); return IMAP_AUTH_FAILURE; } rc = SASL_FAIL; /* If the user hasn't specified a method, use any available */ if (!method) { method = idata->capstr; /* hack for SASL ANONYMOUS support: * 1. Fetch username. If it's "" or "anonymous" then * 2. attempt sasl_client_start with only "AUTH=ANONYMOUS" capability * 3. if sasl_client_start fails, fall through... */ if (mutt_account_getuser (&idata->conn->account)) return IMAP_AUTH_FAILURE; if (mutt_bit_isset (idata->capabilities, AUTH_ANON) && (!idata->conn->account.user[0] || !ascii_strncmp (idata->conn->account.user, "anonymous", 9))) rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, &pc, &olen, &mech); } else if (!ascii_strcasecmp ("login", method) && !strstr (NONULL (idata->capstr), "AUTH=LOGIN")) /* do not use SASL login for regular IMAP login (#3556) */ return IMAP_AUTH_UNAVAIL; if (rc != SASL_OK && rc != SASL_CONTINUE) do { rc = sasl_client_start (saslconn, method, &interaction, &pc, &olen, &mech); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); client_start = (olen > 0); if (rc != SASL_OK && rc != SASL_CONTINUE) { if (method) dprint (2, (debugfile, "imap_auth_sasl: %s unavailable\n", method)); else dprint (1, (debugfile, "imap_auth_sasl: Failure starting authentication exchange. No shared mechanisms?\n")); /* SASL doesn't support LOGIN, so fall back */ return IMAP_AUTH_UNAVAIL; } mutt_message (_("Authenticating (%s)..."), mech); snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech); if (mutt_bit_isset (idata->capabilities, SASL_IR) && client_start) { len = mutt_strlen (buf); buf[len++] = ' '; if (sasl_encode64 (pc, olen, buf + len, sizeof (buf) - len, &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } client_start = olen = 0; } imap_cmd_start (idata, buf); irc = IMAP_CMD_CONTINUE; /* looping protocol */ while (rc == SASL_CONTINUE || olen > 0) { do irc = imap_cmd_step (idata); while (irc == IMAP_CMD_CONTINUE); if (irc == IMAP_CMD_BAD || irc == IMAP_CMD_NO) goto bail; if (irc == IMAP_CMD_RESPOND) { /* Exchange incorrectly returns +\r\n instead of + \r\n */ if (idata->buf[1] == '\0') { buf[0] = '\0'; len = 0; } else if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, LONG_STRING-1, &len) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n")); goto bail; } } /* client-start is only available with the SASL-IR extension, but * SASL 2.1 seems to want to use it regardless, at least for DIGEST * fast reauth. Override if the server sent an initial continuation */ if (!client_start || buf[0]) { do { rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); } else client_start = 0; /* send out response, or line break if none needed */ if (olen) { if (sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } } if (irc == IMAP_CMD_RESPOND) { strfcpy (buf + olen, "\r\n", sizeof (buf) - olen); mutt_socket_write (idata->conn, buf); } /* If SASL has errored out, send an abort string to the server */ if (rc < 0) { mutt_socket_write (idata->conn, "*\r\n"); dprint (1, (debugfile, "imap_auth_sasl: sasl_client_step error %d\n",rc)); } olen = 0; } while (irc != IMAP_CMD_OK) if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; if (rc != SASL_OK) goto bail; if (imap_code (idata->buf)) { mutt_sasl_setup_conn (idata->conn, saslconn); return IMAP_AUTH_SUCCESS; } bail: sasl_dispose (&saslconn); if (method) { dprint (2, (debugfile, "imap_auth_sasl: %s failed\n", method)); return IMAP_AUTH_UNAVAIL; } mutt_error _("SASL authentication failed."); mutt_sleep(2); return IMAP_AUTH_FAILURE; }
static int tls_check_one_certificate (const gnutls_datum_t *certdata, gnutls_certificate_status certstat, const char* hostname, int idx, int len) { int certerr, savedcert; gnutls_x509_crt cert; char buf[SHORT_STRING]; char fpbuf[SHORT_STRING]; size_t buflen; char dn_common_name[SHORT_STRING]; char dn_email[SHORT_STRING]; char dn_organization[SHORT_STRING]; char dn_organizational_unit[SHORT_STRING]; char dn_locality[SHORT_STRING]; char dn_province[SHORT_STRING]; char dn_country[SHORT_STRING]; time_t t; char datestr[30]; MUTTMENU *menu; char helpstr[LONG_STRING]; char title[STRING]; FILE *fp; gnutls_datum pemdata; int i, row, done, ret; if (!tls_check_preauth (certdata, certstat, hostname, idx, &certerr, &savedcert)) return 1; /* skip signers if insecure algorithm was used */ if (idx && (certerr & CERTERR_INSECUREALG)) { if (idx == 1) { mutt_error (_("Warning: Server certificate was signed using an insecure algorithm")); mutt_sleep (2); } return 0; } /* interactive check from user */ if (gnutls_x509_crt_init (&cert) < 0) { mutt_error (_("Error initialising gnutls certificate data")); mutt_sleep (2); return 0; } if (gnutls_x509_crt_import (cert, certdata, GNUTLS_X509_FMT_DER) < 0) { mutt_error (_("Error processing certificate data")); mutt_sleep (2); gnutls_x509_crt_deinit (cert); return -1; } menu = mutt_new_menu (-1); menu->max = 25; menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *)); for (i = 0; i < menu->max; i++) menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char)); row = 0; strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING); row++; buflen = sizeof (dn_common_name); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn_common_name, &buflen) != 0) dn_common_name[0] = '\0'; buflen = sizeof (dn_email); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, dn_email, &buflen) != 0) dn_email[0] = '\0'; buflen = sizeof (dn_organization); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, dn_organization, &buflen) != 0) dn_organization[0] = '\0'; buflen = sizeof (dn_organizational_unit); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, dn_organizational_unit, &buflen) != 0) dn_organizational_unit[0] = '\0'; buflen = sizeof (dn_locality); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, dn_locality, &buflen) != 0) dn_locality[0] = '\0'; buflen = sizeof (dn_province); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, dn_province, &buflen) != 0) dn_province[0] = '\0'; buflen = sizeof (dn_country); if (gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, dn_country, &buflen) != 0) dn_country[0] = '\0'; snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit); snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s", dn_locality, dn_province, dn_country); row++; strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING); row++; buflen = sizeof (dn_common_name); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn_common_name, &buflen) != 0) dn_common_name[0] = '\0'; buflen = sizeof (dn_email); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, dn_email, &buflen) != 0) dn_email[0] = '\0'; buflen = sizeof (dn_organization); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 0, dn_organization, &buflen) != 0) dn_organization[0] = '\0'; buflen = sizeof (dn_organizational_unit); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 0, dn_organizational_unit, &buflen) != 0) dn_organizational_unit[0] = '\0'; buflen = sizeof (dn_locality); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_LOCALITY_NAME, 0, 0, dn_locality, &buflen) != 0) dn_locality[0] = '\0'; buflen = sizeof (dn_province); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 0, dn_province, &buflen) != 0) dn_province[0] = '\0'; buflen = sizeof (dn_country); if (gnutls_x509_crt_get_issuer_dn_by_oid (cert, GNUTLS_OID_X520_COUNTRY_NAME, 0, 0, dn_country, &buflen) != 0) dn_country[0] = '\0'; snprintf (menu->dialog[row++], SHORT_STRING, " %s %s", dn_common_name, dn_email); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organization); snprintf (menu->dialog[row++], SHORT_STRING, " %s", dn_organizational_unit); snprintf (menu->dialog[row++], SHORT_STRING, " %s %s %s", dn_locality, dn_province, dn_country); row++; snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid")); t = gnutls_x509_crt_get_activation_time (cert); snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"), tls_make_date (t, datestr, 30)); t = gnutls_x509_crt_get_expiration_time (cert); snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"), tls_make_date (t, datestr, 30)); fpbuf[0] = '\0'; tls_fingerprint (GNUTLS_DIG_SHA, fpbuf, sizeof (fpbuf), certdata); snprintf (menu->dialog[row++], SHORT_STRING, _("SHA1 Fingerprint: %s"), fpbuf); fpbuf[0] = '\0'; tls_fingerprint (GNUTLS_DIG_MD5, fpbuf, sizeof (fpbuf), certdata); snprintf (menu->dialog[row++], SHORT_STRING, _("MD5 Fingerprint: %s"), fpbuf); if (certerr & CERTERR_NOTYETVALID) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate is not yet valid"), SHORT_STRING); } if (certerr & CERTERR_EXPIRED) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate has expired"), SHORT_STRING); } if (certerr & CERTERR_REVOKED) { row++; strfcpy (menu->dialog[row], _("WARNING: Server certificate has been revoked"), SHORT_STRING); } if (certerr & CERTERR_HOSTNAME) { row++; strfcpy (menu->dialog[row], _("WARNING: Server hostname does not match certificate"), SHORT_STRING); } if (certerr & CERTERR_SIGNERNOTCA) { row++; strfcpy (menu->dialog[row], _("WARNING: Signer of server certificate is not a CA"), SHORT_STRING); } snprintf (title, sizeof (title), _("SSL Certificate check (certificate %d of %d in chain)"), len - idx, len); menu->title = title; /* certificates with bad dates, or that are revoked, must be accepted manually each and every time */ if (SslCertFile && !savedcert && !(certerr & (CERTERR_EXPIRED | CERTERR_NOTYETVALID | CERTERR_REVOKED))) { menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); menu->keys = _("roa"); } else { menu->prompt = _("(r)eject, accept (o)nce"); menu->keys = _("ro"); } helpstr[0] = '\0'; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT); safe_strcat (helpstr, sizeof (helpstr), buf); mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP); safe_strcat (helpstr, sizeof (helpstr), buf); menu->help = helpstr; done = 0; set_option (OPTUNBUFFEREDINPUT); while (!done) { switch (mutt_menuLoop (menu)) { case -1: /* abort */ case OP_MAX + 1: /* reject */ case OP_EXIT: done = 1; break; case OP_MAX + 3: /* accept always */ done = 0; if ((fp = fopen (SslCertFile, "a"))) { /* save hostname if necessary */ if (certerr & CERTERR_HOSTNAME) { fprintf(fp, "#H %s %s\n", hostname, fpbuf); done = 1; } if (certerr & CERTERR_NOTTRUSTED) { done = 0; ret = gnutls_pem_base64_encode_alloc ("CERTIFICATE", certdata, &pemdata); if (ret == 0) { if (fwrite (pemdata.data, pemdata.size, 1, fp) == 1) { done = 1; } gnutls_free (pemdata.data); } } safe_fclose (&fp); } if (!done) { mutt_error (_("Warning: Couldn't save certificate")); mutt_sleep (2); } else { mutt_message (_("Certificate saved")); mutt_sleep (0); } /* fall through */ case OP_MAX + 2: /* accept once */ done = 2; break; } } unset_option (OPTUNBUFFEREDINPUT); mutt_menuDestroy (&menu); gnutls_x509_crt_deinit (cert); return (done == 2); }
/* tls_negotiate: After TLS state has been initialised, attempt to negotiate * TLS over the wire, including certificate checks. */ static int tls_negotiate (CONNECTION * conn) { tlssockdata *data; int err; size_t nproto = 0; /* number of tls/ssl protocols */ data = (tlssockdata *) safe_calloc (1, sizeof (tlssockdata)); conn->sockdata = data; err = gnutls_certificate_allocate_credentials (&data->xcred); if (err < 0) { FREE(&conn->sockdata); mutt_error ("gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err)); mutt_sleep (2); return -1; } gnutls_certificate_set_x509_trust_file (data->xcred, SslCertFile, GNUTLS_X509_FMT_PEM); /* ignore errors, maybe file doesn't exist yet */ if (SslCACertFile) { gnutls_certificate_set_x509_trust_file (data->xcred, SslCACertFile, GNUTLS_X509_FMT_PEM); } if (SslClientCert) { dprint (2, (debugfile, "Using client certificate %s\n", SslClientCert)); gnutls_certificate_set_x509_key_file (data->xcred, SslClientCert, SslClientCert, GNUTLS_X509_FMT_PEM); } #if HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS /* disable checking certificate activation/expiration times in gnutls, we do the checks ourselves */ gnutls_certificate_set_verify_flags(data->xcred, GNUTLS_VERIFY_DISABLE_TIME_CHECKS); #endif if ((err = gnutls_init(&data->state, GNUTLS_CLIENT))) { mutt_error ("gnutls_handshake: %s", gnutls_strerror(err)); mutt_sleep (2); goto fail; } /* set socket */ gnutls_transport_set_ptr (data->state, (gnutls_transport_ptr)conn->fd); if (option(OPTTLSV1_2)) protocol_priority[nproto++] = GNUTLS_TLS1_2; if (option(OPTTLSV1_1)) protocol_priority[nproto++] = GNUTLS_TLS1_1; if (option(OPTTLSV1)) protocol_priority[nproto++] = GNUTLS_TLS1; if (option(OPTSSLV3)) protocol_priority[nproto++] = GNUTLS_SSL3; protocol_priority[nproto] = 0; /* disable TLS/SSL protocols as needed */ if (nproto == 0) { mutt_error (_("All available protocols for TLS/SSL connection disabled")); goto fail; } /* else use the list set above */ /* We use default priorities (see gnutls documentation), except for protocol version */ gnutls_set_default_priority (data->state); gnutls_protocol_set_priority (data->state, protocol_priority); if (SslDHPrimeBits > 0) { gnutls_dh_set_prime_bits (data->state, SslDHPrimeBits); } /* gnutls_set_cred (data->state, GNUTLS_ANON, NULL); */ gnutls_credentials_set (data->state, GNUTLS_CRD_CERTIFICATE, data->xcred); err = gnutls_handshake(data->state); while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED) { err = gnutls_handshake(data->state); } if (err < 0) { if (err == GNUTLS_E_FATAL_ALERT_RECEIVED) { mutt_error("gnutls_handshake: %s(%s)", gnutls_strerror(err), gnutls_alert_get_name(gnutls_alert_get(data->state))); } else { mutt_error("gnutls_handshake: %s", gnutls_strerror(err)); } mutt_sleep (2); goto fail; } if (!tls_check_certificate(conn)) goto fail; /* set Security Strength Factor (SSF) for SASL */ /* NB: gnutls_cipher_get_key_size() returns key length in bytes */ conn->ssf = gnutls_cipher_get_key_size (gnutls_cipher_get (data->state)) * 8; tls_get_client_cert (conn); if (!option(OPTNOCURSES)) { mutt_message (_("SSL/TLS connection using %s (%s/%s/%s)"), gnutls_protocol_get_name (gnutls_protocol_get_version (data->state)), gnutls_kx_get_name (gnutls_kx_get (data->state)), gnutls_cipher_get_name (gnutls_cipher_get (data->state)), gnutls_mac_get_name (gnutls_mac_get (data->state))); mutt_sleep (0); } return 0; fail: gnutls_certificate_free_credentials (data->xcred); gnutls_deinit (data->state); FREE(&conn->sockdata); return -1; }
int mutt_slow_close_compressed (CONTEXT * ctx) { FILE *fp; const char *append; char *cmd; COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo; debug_print (2, ("called on '%s'\n", ctx->path)); if (!(ctx->append && ((append = get_append_command (ctx->realpath, ctx)) || (append = ci->close)))) { /* if we can not or should not append, * we only have to remove the compressed info, because sync was already * called */ mutt_fast_close_compressed (ctx); return (0); } if (ctx->fp) fclose (ctx->fp); ctx->fp = NULL; if (!ctx->quiet) { if (append == ci->close) mutt_message (_("Compressing %s..."), ctx->realpath); else mutt_message (_("Compressed-appending to %s..."), ctx->realpath); } cmd = get_compression_cmd (append, ctx); if (cmd == NULL) return (-1); if ((fp = fopen (ctx->realpath, "a")) == NULL) { mutt_perror (ctx->realpath); mem_free (&cmd); return (-1); } mutt_block_signals (); if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) { fclose (fp); mutt_unblock_signals (); mutt_error _("Unable to lock mailbox!"); mem_free (&cmd); return (-1); } debug_print (2, ("CompressCmd: '%s'\n", cmd)); endwin (); fflush (stdout); if (append == ci->close) sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath); else sprintf (echo_cmd, _("echo Compressed-appending to %s..."), ctx->realpath); mutt_system (echo_cmd); if (mutt_system (cmd)) { mutt_any_key_to_continue (NULL); mutt_error (_ (" %s: Error compressing mailbox! Uncompressed one kept!\n"), ctx->path); mem_free (&cmd); mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); return (-1); } mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); remove_file (ctx); restore_path (ctx); mem_free (&cmd); mem_free (&ctx->compressinfo); return (0); }
int mutt_open_read_compressed (CONTEXT * ctx) { char *cmd; FILE *fp; int rc; COMPRESS_INFO *ci = set_compress_info (ctx); if (!ci->open) { ctx->magic = 0; mem_free (ctx->compressinfo); return (-1); } if (!ci->close || access (ctx->path, W_OK) != 0) ctx->readonly = 1; set_path (ctx); store_size (ctx); if (!ctx->quiet) mutt_message (_("Decompressing %s..."), ctx->realpath); cmd = get_compression_cmd (ci->open, ctx); if (cmd == NULL) return (-1); debug_print (2, ("DecompressCmd: '%s'\n", cmd)); if ((fp = fopen (ctx->realpath, "r")) == NULL) { mutt_perror (ctx->realpath); mem_free (&cmd); return (-1); } mutt_block_signals (); if (mbox_lock_compressed (ctx, fp, 0, 1) == -1) { fclose (fp); mutt_unblock_signals (); mutt_error _("Unable to lock mailbox!"); mem_free (&cmd); return (-1); } endwin (); fflush (stdout); sprintf (echo_cmd, _("echo Decompressing %s..."), ctx->realpath); mutt_system (echo_cmd); rc = mutt_system (cmd); mbox_unlock_compressed (ctx, fp); mutt_unblock_signals (); fclose (fp); if (rc) { mutt_any_key_to_continue (NULL); ctx->magic = 0; mem_free (ctx->compressinfo); mutt_error (_("Error executing: %s : unable to open the mailbox!\n"), cmd); } mem_free (&cmd); if (rc) return (-1); if (mutt_check_mailbox_compressed (ctx)) return (-1); ctx->magic = mx_get_magic (ctx->path); return (0); }
static int interactive_check_cert (X509 *cert, int idx, int len) { static const char * const part[] = {"/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C="}; char helpstr[LONG_STRING]; char buf[STRING]; char title[STRING]; MUTTMENU *menu = mutt_new_menu (-1); int done, row, i; FILE *fp; char *name = NULL, *c; dprint (2, (debugfile, "interactive_check_cert: %s\n", cert->name)); menu->max = 19; menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *)); for (i = 0; i < menu->max; i++) menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char)); row = 0; strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING); row++; name = X509_NAME_oneline (X509_get_subject_name (cert), buf, sizeof (buf)); dprint (2, (debugfile, "oneline: %s\n", name)); for (i = 0; i < 5; i++) { c = x509_get_part (name, part[i]); snprintf (menu->dialog[row++], SHORT_STRING, " %s", c); } row++; strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING); row++; name = X509_NAME_oneline (X509_get_issuer_name (cert), buf, sizeof (buf)); for (i = 0; i < 5; i++) { c = x509_get_part (name, part[i]); snprintf (menu->dialog[row++], SHORT_STRING, " %s", c); } row++; snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid")); snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"), asn1time_to_string (X509_get_notBefore (cert))); snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"), asn1time_to_string (X509_get_notAfter (cert))); row++; buf[0] = '\0'; x509_fingerprint (buf, sizeof (buf), cert); snprintf (menu->dialog[row++], SHORT_STRING, _("Fingerprint: %s"), buf); snprintf (title, sizeof (title), _("SSL Certificate check (certificate %d of %d in chain)"), len - idx, len); menu->title = title; if (SslCertFile && (option (OPTSSLVERIFYDATES) == M_NO || (X509_cmp_current_time (X509_get_notAfter (cert)) >= 0 && X509_cmp_current_time (X509_get_notBefore (cert)) < 0))) { menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); menu->keys = _("roa"); } else { menu->prompt = _("(r)eject, accept (o)nce"); menu->keys = _("ro"); } helpstr[0] = '\0'; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT); safe_strcat (helpstr, sizeof (helpstr), buf); mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP); safe_strcat (helpstr, sizeof (helpstr), buf); menu->help = helpstr; done = 0; set_option(OPTUNBUFFEREDINPUT); while (!done) { switch (mutt_menuLoop (menu)) { case -1: /* abort */ case OP_MAX + 1: /* reject */ case OP_EXIT: done = 1; break; case OP_MAX + 3: /* accept always */ done = 0; if ((fp = fopen (SslCertFile, "a"))) { if (PEM_write_X509 (fp, cert)) done = 1; safe_fclose (&fp); } if (!done) { mutt_error (_("Warning: Couldn't save certificate")); mutt_sleep (2); } else { mutt_message (_("Certificate saved")); mutt_sleep (0); } /* fall through */ case OP_MAX + 2: /* accept once */ done = 2; ssl_cache_trusted_cert (cert); break; } } unset_option(OPTUNBUFFEREDINPUT); mutt_menuDestroy (&menu); dprint (2, (debugfile, "ssl interactive_check_cert: done=%d\n", done)); return (done == 2); }
pgp_key_t pgp_getkeybyaddr (ADDRESS * a, short abilities, pgp_ring_t keyring, int oppenc_mode) { ADDRESS *r, *p; LIST *hints = NULL; int multi = 0; int match; pgp_key_t keys, k, kn; pgp_key_t the_strong_valid_key = NULL; pgp_key_t a_valid_addrmatch_key = NULL; pgp_key_t matches = NULL; pgp_key_t *last = &matches; pgp_uid_t *q; if (a && a->mailbox) hints = pgp_add_string_to_hints (hints, a->mailbox); if (a && a->personal) hints = pgp_add_string_to_hints (hints, a->personal); if (! oppenc_mode ) mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); keys = pgp_get_candidates (keyring, hints); mutt_free_list (&hints); if (!keys) return NULL; dprint (5, (debugfile, "pgp_getkeybyaddr: looking for %s <%s>.", a->personal, a->mailbox)); for (k = keys; k; k = kn) { kn = k->next; dprint (5, (debugfile, " looking at key: %s\n", pgp_keyid (k))); if (abilities && !(k->flags & abilities)) { dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n", k->flags, abilities)); continue; } match = 0; /* any match */ for (q = k->address; q; q = q->next) { r = rfc822_parse_adrlist (NULL, NONULL (q->addr)); for (p = r; p; p = p->next) { int validity = pgp_id_matches_addr (a, p, q); if (validity & PGP_KV_MATCH) /* something matches */ match = 1; if ((validity & PGP_KV_VALID) && (validity & PGP_KV_ADDR)) { if (validity & PGP_KV_STRONGID) { if (the_strong_valid_key && the_strong_valid_key != k) multi = 1; the_strong_valid_key = k; } else { a_valid_addrmatch_key = k; } } } rfc822_free_address (&r); } if (match) { *last = pgp_principal_key (k); kn = pgp_remove_key (&keys, *last); last = pgp_get_lastp (k); } } pgp_free_key (&keys); if (matches) { if (oppenc_mode) { if (the_strong_valid_key) { pgp_remove_key (&matches, the_strong_valid_key); k = the_strong_valid_key; } else if (a_valid_addrmatch_key) { pgp_remove_key (&matches, a_valid_addrmatch_key); k = a_valid_addrmatch_key; } else k = NULL; } else if (the_strong_valid_key && !multi) { /* * There was precisely one strong match on a valid ID. * * Proceed without asking the user. */ pgp_remove_key (&matches, the_strong_valid_key); k = the_strong_valid_key; } else { /* * Else: Ask the user. */ if ((k = pgp_select_key (matches, a, NULL))) pgp_remove_key (&matches, k); } pgp_free_key (&matches); return k; } return NULL; }
static pgp_key_t pgp_select_key (pgp_key_t keys, ADDRESS * p, const char *s) { int keymax; pgp_uid_t **KeyTable; MUTTMENU *menu; int i, done = 0; char helpstr[LONG_STRING], buf[LONG_STRING], tmpbuf[STRING]; char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; FILE *fp, *devnull; pid_t thepid; pgp_key_t kp; pgp_uid_t *a; int (*f) (const void *, const void *); int unusable = 0; keymax = 0; KeyTable = NULL; for (i = 0, kp = keys; kp; kp = kp->next) { if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) { unusable = 1; continue; } for (a = kp->address; a; a = a->next) { if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) { unusable = 1; continue; } if (i == keymax) { keymax += 5; safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax); } KeyTable[i++] = a; } } if (!i && unusable) { mutt_error _("All matching keys are expired, revoked, or disabled."); mutt_sleep (1); return NULL; } switch (PgpSortKeys & SORT_MASK) { case SORT_DATE: f = pgp_compare_date; break; case SORT_KEYID: f = pgp_compare_keyid; break; case SORT_ADDRESS: f = pgp_compare_address; break; case SORT_TRUST: default: f = pgp_compare_trust; break; } qsort (KeyTable, i, sizeof (pgp_uid_t *), f); helpstr[0] = 0; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP, OP_GENERIC_SELECT_ENTRY); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP, OP_VERIFY_KEY); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP); strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ menu = mutt_new_menu (MENU_PGP); menu->max = i; menu->make_entry = pgp_entry; menu->help = helpstr; menu->data = KeyTable; if (p) snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox); else snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s); menu->title = buf; kp = NULL; mutt_clear_error (); while (!done) { switch (mutt_menuLoop (menu)) { case OP_VERIFY_KEY: mutt_mktemp (tempfile, sizeof (tempfile)); if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */ { mutt_perror _("Can't open /dev/null"); break; } if ((fp = safe_fopen (tempfile, "w")) == NULL) { safe_fclose (&devnull); mutt_perror _("Can't create temporary file"); break; } mutt_message _("Invoking PGP..."); snprintf (tmpbuf, sizeof (tmpbuf), "0x%s", pgp_fpr_or_lkeyid (pgp_principal_key (KeyTable[menu->current]->parent))); if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1, fileno (fp), fileno (devnull), tmpbuf)) == -1) { mutt_perror _("Can't create filter"); unlink (tempfile); safe_fclose (&fp); safe_fclose (&devnull); } mutt_wait_filter (thepid); safe_fclose (&fp); safe_fclose (&devnull); mutt_clear_error (); snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent))); mutt_do_pager (cmd, tempfile, 0, NULL); menu->redraw = REDRAW_FULL; break; case OP_VIEW_ID: mutt_message ("%s", NONULL (KeyTable[menu->current]->addr)); break; case OP_GENERIC_SELECT_ENTRY: /* XXX make error reporting more verbose */ if (option (OPTPGPCHECKTRUST)) if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) { mutt_error _("This key can't be used: expired/disabled/revoked."); break; } if (option (OPTPGPCHECKTRUST) && (!pgp_id_is_valid (KeyTable[menu->current]) || !pgp_id_is_strong (KeyTable[menu->current]))) { char *s = ""; char buff[LONG_STRING]; if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE) s = N_("ID is expired/disabled/revoked."); else switch (KeyTable[menu->current]->trust & 0x03) { case 0: s = N_("ID has undefined validity."); break; case 1: s = N_("ID is not valid."); break; case 2: s = N_("ID is only marginally valid."); break; } snprintf (buff, sizeof (buff), _("%s Do you really want to use the key?"), _(s)); if (mutt_yesorno (buff, M_NO) != M_YES) { mutt_clear_error (); break; } } # if 0 kp = pgp_principal_key (KeyTable[menu->current]->parent); # else kp = KeyTable[menu->current]->parent; # endif done = 1; break; case OP_EXIT: kp = NULL; done = 1; break; } } mutt_menuDestroy (&menu); FREE (&KeyTable); set_option (OPTNEEDREDRAW); return (kp); }
pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring) { LIST *hints = NULL; pgp_key_t keys; pgp_key_t matches = NULL; pgp_key_t *last = &matches; pgp_key_t k, kn; pgp_uid_t *a; short match; size_t l; const char *ps, *pl; if ((l = mutt_strlen (p)) && p[l-1] == '!') p[l-1] = 0; mutt_message (_("Looking for keys matching \"%s\"..."), p); hints = pgp_add_string_to_hints (hints, p); keys = pgp_get_candidates (keyring, hints); mutt_free_list (&hints); if (!keys) goto out; /* User input may be short or long key ID, independent of OPTPGPLONGIDS. * pgp_key_t->keyid should always contain a long key ID without 0x. * Strip leading "0x" before loops so it doesn't have to be done over and * over again, and prepare pl and ps to simplify logic in the loop's inner * condition. */ pl = (!mutt_strncasecmp (p, "0x", 2) ? p + 2 : p); ps = (mutt_strlen (pl) == 16 ? pl + 8 : pl); for (k = keys; k; k = kn) { kn = k->next; if (abilities && !(k->flags & abilities)) continue; /* This shouldn't happen, but keys without any addresses aren't selectable * in pgp_select_key(). */ if (!k->address) continue; match = 0; dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s:\n", p, pgp_long_keyid (k))); /* If ps != pl it means a long ID (or name of 16 characters) was given, do * not attempt to match short IDs then. Also, it is unnecessary to try to * match pl against long IDs if ps == pl as pl could not be a long ID. */ if (!*p || (ps != pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || (ps == pl && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; } else { for (a = k->address; a; a = a->next) { dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\":\n", p, pgp_long_keyid (k), NONULL (a->addr))); if (mutt_stristr (a->addr, p)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; break; } } } if (match) { *last = pgp_principal_key (k); kn = pgp_remove_key (&keys, *last); last = pgp_get_lastp (k); } } pgp_free_key (&keys); if (matches) { if ((k = pgp_select_key (matches, NULL, p))) pgp_remove_key (&matches, k); pgp_free_key (&matches); if (l && !p[l-1]) p[l-1] = '!'; return k; } out: if (l && !p[l-1]) p[l-1] = '!'; return NULL; }
pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring) { LIST *hints = NULL; pgp_key_t keys; pgp_key_t matches = NULL; pgp_key_t *last = &matches; pgp_key_t k, kn; pgp_uid_t *a; short match; size_t l; const char *ps, *pl, *pfcopy, *phint; if ((l = mutt_strlen (p)) && p[l-1] == '!') p[l-1] = 0; mutt_message (_("Looking for keys matching \"%s\"..."), p); pfcopy = crypt_get_fingerprint_or_id (p, &phint, &pl, &ps); hints = pgp_add_string_to_hints (hints, phint); keys = pgp_get_candidates (keyring, hints); mutt_free_list (&hints); if (!keys) goto out; for (k = keys; k; k = kn) { kn = k->next; if (abilities && !(k->flags & abilities)) continue; /* This shouldn't happen, but keys without any addresses aren't selectable * in pgp_select_key(). */ if (!k->address) continue; match = 0; dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s:\n", p, pgp_long_keyid (k))); if (!*p || (pfcopy && mutt_strcasecmp (pfcopy, k->fingerprint) == 0) || (pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || (ps && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; } else { for (a = k->address; a; a = a->next) { dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\":\n", p, pgp_long_keyid (k), NONULL (a->addr))); if (mutt_stristr (a->addr, p)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; break; } } } if (match) { *last = pgp_principal_key (k); kn = pgp_remove_key (&keys, *last); last = pgp_get_lastp (k); } } pgp_free_key (&keys); if (matches) { if ((k = pgp_select_key (matches, NULL, p))) pgp_remove_key (&matches, k); pgp_free_key (&matches); FREE (&pfcopy); if (l && !p[l-1]) p[l-1] = '!'; return k; } out: FREE (&pfcopy); if (l && !p[l-1]) p[l-1] = '!'; return NULL; }
int mutt_is_application_smime (BODY *m) { char *t=NULL; int len, complain=0; if(!m) return 0; if ((m->type & TYPEAPPLICATION) && m->subtype) { /* S/MIME MIME types don't need x- anymore, see RFC2311 */ if (!ascii_strcasecmp (m->subtype, "x-pkcs7-mime") || !ascii_strcasecmp (m->subtype, "pkcs7-mime")) { if ((t = mutt_get_parameter ("smime-type", m->parameter))) { if (!ascii_strcasecmp (t, "enveloped-data")) return SMIMEENCRYPT; else if (!ascii_strcasecmp (t, "signed-data")) return (SMIMESIGN|SMIMEOPAQUE); else return 0; } /* Netscape 4.7 uses * Content-Description: S/MIME Encrypted Message * instead of Content-Type parameter */ if (!ascii_strcasecmp (m->description, "S/MIME Encrypted Message")) return SMIMEENCRYPT; complain = 1; } else if (ascii_strcasecmp (m->subtype, "octet-stream")) return 0; t = mutt_get_parameter ("name", m->parameter); if (!t) t = m->d_filename; if (!t) t = m->filename; if (!t) { if (complain) mutt_message (_("S/MIME messages with no hints on content are unsupported.")); return 0; } /* no .p7c, .p10 support yet. */ len = mutt_strlen (t) - 4; if (len > 0 && *(t+len) == '.') { len++; if (!ascii_strcasecmp ((t+len), "p7m")) #if 0 return SMIMEENCRYPT; #else /* Not sure if this is the correct thing to do, but it's required for compatibility with Outlook */ return (SMIMESIGN|SMIMEOPAQUE); #endif else if (!ascii_strcasecmp ((t+len), "p7s")) return (SMIMESIGN|SMIMEOPAQUE); }