/** * tls_set_priority - Set TLS algorithm priorities * @param data TLS socket data * @retval 0 Success * @retval -1 Error */ static int tls_set_priority(struct TlsSockData *data) { size_t nproto = 4; size_t priority_size; priority_size = mutt_str_strlen(C_SslCiphers) + 128; char *priority = mutt_mem_malloc(priority_size); priority[0] = '\0'; if (C_SslCiphers) mutt_str_strcat(priority, priority_size, C_SslCiphers); else mutt_str_strcat(priority, priority_size, "NORMAL"); if (!C_SslUseTlsv12) { nproto--; mutt_str_strcat(priority, priority_size, ":-VERS-TLS1.2"); } if (!C_SslUseTlsv11) { nproto--; mutt_str_strcat(priority, priority_size, ":-VERS-TLS1.1"); } if (!C_SslUseTlsv1) { nproto--; mutt_str_strcat(priority, priority_size, ":-VERS-TLS1.0"); } if (!C_SslUseSslv3) { nproto--; mutt_str_strcat(priority, priority_size, ":-VERS-SSL3.0"); } if (nproto == 0) { mutt_error(_("All available protocols for TLS/SSL connection disabled")); FREE(&priority); return -1; } int err = gnutls_priority_set_direct(data->state, priority, NULL); if (err < 0) { mutt_error("gnutls_priority_set_direct(%s): %s", priority, gnutls_strerror(err)); FREE(&priority); return -1; } FREE(&priority); return 0; }
/** * 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; }
/** * mutt_enter_fname_full - Ask the user to select a file * @param[in] prompt Prompt * @param[in] buf Buffer for the result * @param[in] buflen Length of the buffer * @param[in] mailbox If true, select mailboxes * @param[in] multiple Allow multiple selections * @param[out] files List of files selected * @param[out] numfiles Number of files selected * @param[in] flags Flags, see #SelectFileFlags * @retval 0 Success * @retval -1 Error */ int mutt_enter_fname_full(const char *prompt, char *buf, size_t buflen, bool mailbox, bool multiple, char ***files, int *numfiles, SelectFileFlags flags) { struct Event ch; SETCOLOR(MT_COLOR_PROMPT); mutt_window_mvaddstr(MuttMessageWindow, 0, 0, (char *) prompt); addstr(_(" ('?' for list): ")); NORMAL_COLOR; if (buf[0] != '\0') addstr(buf); mutt_window_clrtoeol(MuttMessageWindow); mutt_refresh(); do { ch = mutt_getch(); } while (ch.ch == -2); if (ch.ch < 0) { mutt_window_clearline(MuttMessageWindow, 0); return -1; } else if (ch.ch == '?') { mutt_refresh(); buf[0] = '\0'; if (!flags) flags = MUTT_SEL_FOLDER; if (multiple) flags |= MUTT_SEL_MULTI; if (mailbox) flags |= MUTT_SEL_MAILBOX; mutt_select_file(buf, buflen, flags, files, numfiles); } else { char *pc = mutt_mem_malloc(mutt_str_strlen(prompt) + 3); sprintf(pc, "%s: ", prompt); mutt_unget_event(ch.op ? 0 : ch.ch, ch.op ? ch.op : 0); if (mutt_get_field_full(pc, buf, buflen, (mailbox ? MUTT_EFILE : MUTT_FILE) | MUTT_CLEAR, multiple, files, numfiles) != 0) { buf[0] = '\0'; } FREE(&pc); } return 0; }
/** * ssl_dprint_err_stack - Dump the SSL error stack */ static void ssl_dprint_err_stack(void) { BIO *bio = NULL; char *buf = NULL; long buflen; char *output = NULL; bio = BIO_new(BIO_s_mem()); if (!bio) return; ERR_print_errors(bio); buflen = BIO_get_mem_data(bio, &buf); if (buflen > 0) { output = mutt_mem_malloc(buflen + 1); memcpy(output, buf, buflen); output[buflen] = '\0'; mutt_debug(LL_DEBUG1, "SSL error stack: %s\n", output); FREE(&output); } BIO_free(bio); }
/** * cs_new - Create a new Config Set * @param size Number of expected config items * @retval ptr New ConfigSet object */ struct ConfigSet *cs_new(size_t size) { struct ConfigSet *cs = mutt_mem_malloc(sizeof(*cs)); cs_init(cs, size); return cs; }
/** * check_host - Check the host on the certificate * @param x509cert Certificate * @param hostname Hostname * @param err Buffer for error message * @param errlen Length of buffer * @retval 1 Hostname matches the certificate * @retval 0 Error */ static int check_host(X509 *x509cert, const char *hostname, char *err, size_t errlen) { int rc = 0; /* hostname in ASCII format: */ char *hostname_ascii = NULL; /* needed to get the common name: */ X509_NAME *x509_subject = NULL; char *buf = NULL; int bufsize; /* needed to get the DNS subjectAltNames: */ STACK_OF(GENERAL_NAME) * subj_alt_names; int subj_alt_names_count; GENERAL_NAME *subj_alt_name = NULL; /* did we find a name matching hostname? */ bool match_found; /* Check if 'hostname' matches the one of the subjectAltName extensions of * type DNS or the Common Name (CN). */ #ifdef HAVE_LIBIDN if (mutt_idna_to_ascii_lz(hostname, &hostname_ascii, 0) != 0) { hostname_ascii = mutt_str_strdup(hostname); } #else hostname_ascii = mutt_str_strdup(hostname); #endif /* Try the DNS subjectAltNames. */ match_found = false; subj_alt_names = X509_get_ext_d2i(x509cert, NID_subject_alt_name, NULL, NULL); if (subj_alt_names) { subj_alt_names_count = sk_GENERAL_NAME_num(subj_alt_names); for (int i = 0; i < subj_alt_names_count; i++) { subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i); if (subj_alt_name->type == GEN_DNS) { if ((subj_alt_name->d.ia5->length >= 0) && (mutt_str_strlen((char *) subj_alt_name->d.ia5->data) == (size_t) subj_alt_name->d.ia5->length) && (match_found = hostname_match(hostname_ascii, (char *) (subj_alt_name->d.ia5->data)))) { break; } } } GENERAL_NAMES_free(subj_alt_names); } if (!match_found) { /* Try the common name */ x509_subject = X509_get_subject_name(x509cert); if (!x509_subject) { if (err && errlen) mutt_str_strfcpy(err, _("cannot get certificate subject"), errlen); goto out; } /* first get the space requirements */ bufsize = X509_NAME_get_text_by_NID(x509_subject, NID_commonName, NULL, 0); if (bufsize == -1) { if (err && errlen) mutt_str_strfcpy(err, _("cannot get certificate common name"), errlen); goto out; } bufsize++; /* space for the terminal nul char */ buf = mutt_mem_malloc((size_t) bufsize); if (X509_NAME_get_text_by_NID(x509_subject, NID_commonName, buf, bufsize) == -1) { if (err && errlen) mutt_str_strfcpy(err, _("cannot get certificate common name"), errlen); goto out; } /* cast is safe since bufsize is incremented above, so bufsize-1 is always * zero or greater. */ if (mutt_str_strlen(buf) == (size_t) bufsize - 1) { match_found = hostname_match(hostname_ascii, buf); } } if (!match_found) { if (err && errlen) snprintf(err, errlen, _("certificate owner does not match hostname %s"), hostname); goto out; } rc = 1; out: FREE(&buf); FREE(&hostname_ascii); return rc; }
/** * mutt_draw_tree - Draw a tree of threaded emails * @param ctx Mailbox * * Since the graphics characters have a value >255, I have to resort to using * escape sequences to pass the information to print_enriched_string(). These * are the macros MUTT_TREE_* defined in mutt.h. * * ncurses should automatically use the default ASCII characters instead of * graphics chars on terminals which don't support them (see the man page for * curs_addch). */ void mutt_draw_tree(struct Context *ctx) { char *pfx = NULL, *mypfx = NULL, *arrow = NULL, *myarrow = NULL, *new_tree = NULL; enum TreeChar corner = (C_Sort & SORT_REVERSE) ? MUTT_TREE_ULCORNER : MUTT_TREE_LLCORNER; enum TreeChar vtee = (C_Sort & SORT_REVERSE) ? MUTT_TREE_BTEE : MUTT_TREE_TTEE; int depth = 0, start_depth = 0, max_depth = 0, width = C_NarrowTree ? 1 : 2; struct MuttThread *nextdisp = NULL, *pseudo = NULL, *parent = NULL, *tree = ctx->tree; /* Do the visibility calculations and free the old thread chars. * From now on we can simply ignore invisible subtrees */ calculate_visibility(ctx, &max_depth); pfx = mutt_mem_malloc(width * max_depth + 2); arrow = mutt_mem_malloc(width * max_depth + 2); while (tree) { if (depth) { myarrow = arrow + (depth - start_depth - (start_depth ? 0 : 1)) * width; if (depth && (start_depth == depth)) myarrow[0] = nextdisp ? MUTT_TREE_LTEE : corner; else if (parent->message && !C_HideLimited) myarrow[0] = MUTT_TREE_HIDDEN; else if (!parent->message && !C_HideMissing) myarrow[0] = MUTT_TREE_MISSING; else myarrow[0] = vtee; if (width == 2) { myarrow[1] = pseudo ? MUTT_TREE_STAR : (tree->duplicate_thread ? MUTT_TREE_EQUALS : MUTT_TREE_HLINE); } if (tree->visible) { myarrow[width] = MUTT_TREE_RARROW; myarrow[width + 1] = 0; new_tree = mutt_mem_malloc((2 + depth * width)); if (start_depth > 1) { strncpy(new_tree, pfx, (start_depth - 1) * width); mutt_str_strfcpy(new_tree + (start_depth - 1) * width, arrow, (1 + depth - start_depth) * width + 2); } else mutt_str_strfcpy(new_tree, arrow, 2 + depth * width); tree->message->tree = new_tree; } } if (tree->child && depth) { mypfx = pfx + (depth - 1) * width; mypfx[0] = nextdisp ? MUTT_TREE_VLINE : MUTT_TREE_SPACE; if (width == 2) mypfx[1] = MUTT_TREE_SPACE; } parent = tree; nextdisp = NULL; pseudo = NULL; do { if (tree->child && tree->subtree_visible) { if (tree->deep) depth++; if (tree->visible) start_depth = depth; tree = tree->child; /* we do this here because we need to make sure that the first child thread * of the old tree that we deal with is actually displayed if any are, * or we might set the parent variable wrong while going through it. */ while (!tree->subtree_visible && tree->next) tree = tree->next; } else { while (!tree->next && tree->parent) { if (tree == pseudo) pseudo = NULL; if (tree == nextdisp) nextdisp = NULL; if (tree->visible) start_depth = depth; tree = tree->parent; if (tree->deep) { if (start_depth == depth) start_depth--; depth--; } } if (tree == pseudo) pseudo = NULL; if (tree == nextdisp) nextdisp = NULL; if (tree->visible) start_depth = depth; tree = tree->next; if (!tree) break; } if (!pseudo && tree->fake_thread) pseudo = tree; if (!nextdisp && tree->next_subtree_visible) nextdisp = tree; } while (!tree->deep); } FREE(&pfx); FREE(&arrow); }