static bool test_string_set(struct ConfigSet *cs, struct Buffer *err) { log_line(__func__); const char *valid[] = { "*****@*****.**", "*****@*****.**", NULL }; const char *name = "Damson"; char *addr = NULL; int rc; for (unsigned int i = 0; i < mutt_array_size(valid); i++) { mutt_buffer_reset(err); rc = cs_str_string_set(cs, name, valid[i], err); if (!TEST_CHECK(CSR_RESULT(rc) == CSR_SUCCESS)) { TEST_MSG("%s\n", err->data); return false; } addr = VarDamson ? VarDamson->mailbox : NULL; if (!TEST_CHECK(mutt_str_strcmp(addr, valid[i]) == 0)) { TEST_MSG("Value of %s wasn't changed\n", name); return false; } TEST_MSG("%s = '%s', set by '%s'\n", name, NONULL(addr), NONULL(valid[i])); } name = "Elderberry"; for (unsigned int i = 0; i < mutt_array_size(valid); i++) { mutt_buffer_reset(err); rc = cs_str_string_set(cs, name, valid[i], err); if (!TEST_CHECK(CSR_RESULT(rc) == CSR_SUCCESS)) { TEST_MSG("%s\n", err->data); return false; } addr = VarElderberry ? VarElderberry->mailbox : NULL; if (!TEST_CHECK(mutt_str_strcmp(addr, valid[i]) == 0)) { TEST_MSG("Value of %s wasn't changed\n", name); return false; } TEST_MSG("%s = '%s', set by '%s'\n", name, NONULL(addr), NONULL(valid[i])); } log_line(__func__); return true; }
/** * cs_notify_listeners - Notify all listeners of an event * @param cs Config items * @param he HashElem representing config item * @param name Name of config item * @param ev Type of event */ void cs_notify_listeners(const struct ConfigSet *cs, struct HashElem *he, const char *name, enum ConfigEvent ev) { if (!cs || !he || !name) return; for (size_t i = 0; i < mutt_array_size(cs->listeners); i++) { if (!cs->listeners[i]) return; cs->listeners[i](cs, he, name, ev); } }
/** * cs_add_listener - Add a listener (callback function) * @param cs Config items * @param fn Listener callback function */ void cs_add_listener(struct ConfigSet *cs, cs_listener fn) { if (!cs || !fn) return; for (size_t i = 0; i < mutt_array_size(cs->listeners); i++) { if (cs->listeners[i] == fn) { mutt_debug(LL_DEBUG1, "Listener was already registered\n"); return; } } for (size_t i = 0; i < mutt_array_size(cs->listeners); i++) { if (!cs->listeners[i]) { cs->listeners[i] = fn; return; } } }
/** * cs_get_type_def - Get the definition for a type * @param cs Config items * @param type Type to lookup, e.g. #DT_NUMBER * @retval ptr ConfigSetType representing the type */ const struct ConfigSetType *cs_get_type_def(const struct ConfigSet *cs, unsigned int type) { if (!cs) return NULL; type = DTYPE(type); if ((type < 1) || (type >= mutt_array_size(cs->types))) return NULL; if (!cs->types[type].name) return NULL; return &cs->types[type]; }
/** * cs_remove_listener - Remove a listener (callback function) * @param cs Config items * @param fn Listener callback function */ void cs_remove_listener(struct ConfigSet *cs, cs_listener fn) { if (!cs || !fn) return; for (size_t i = 0; i < mutt_array_size(cs->listeners); i++) { if (cs->listeners[i] == fn) { cs->listeners[i] = NULL; return; } } mutt_debug(LL_DEBUG1, "Listener wasn't registered\n"); }
/** * cs_register_type - Register a type of config item * @param cs Config items * @param type Object type, e.g. #DT_BOOL * @param cst Structure defining the type * @retval bool True, if type was registered successfully */ bool cs_register_type(struct ConfigSet *cs, unsigned int type, const struct ConfigSetType *cst) { if (!cs || !cst) return false; if (!cst->name || !cst->string_set || !cst->string_get || !cst->reset || !cst->native_set || !cst->native_get) { return false; } if (type >= mutt_array_size(cs->types)) return false; if (cs->types[type].name) return false; /* already registered */ cs->types[type] = *cst; return true; }
/** * interactive_check_cert - Ask the user if a certificate is valid * @param cert Certificate * @param idx Place of certificate in the chain * @param len Length of the certificate chain * @param ssl SSL state * @param allow_always If certificate may be always allowed * @retval true User selected 'skip' * @retval false Otherwise */ static bool interactive_check_cert(X509 *cert, int idx, size_t len, SSL *ssl, bool allow_always) { static const int part[] = { NID_commonName, /* CN */ NID_pkcs9_emailAddress, /* Email */ NID_organizationName, /* O */ NID_organizationalUnitName, /* OU */ NID_localityName, /* L */ NID_stateOrProvinceName, /* ST */ NID_countryName, /* C */ }; X509_NAME *x509_subject = NULL; X509_NAME *x509_issuer = NULL; char helpstr[1024]; char buf[256]; char title[256]; struct Menu *menu = mutt_menu_new(MENU_GENERIC); int done, row; FILE *fp = NULL; int ALLOW_SKIP = 0; /* All caps tells Coverity that this is effectively a preproc condition */ mutt_menu_push_current(menu); menu->max = mutt_array_size(part) * 2 + 11; menu->dialog = mutt_mem_calloc(1, menu->max * sizeof(char *)); for (int i = 0; i < menu->max; i++) menu->dialog[i] = mutt_mem_calloc(1, dialog_row_len * sizeof(char)); row = 0; mutt_str_strfcpy(menu->dialog[row], _("This certificate belongs to:"), dialog_row_len); row++; x509_subject = X509_get_subject_name(cert); for (unsigned int u = 0; u < mutt_array_size(part); u++) { snprintf(menu->dialog[row++], dialog_row_len, " %s", x509_get_part(x509_subject, part[u])); } row++; mutt_str_strfcpy(menu->dialog[row], _("This certificate was issued by:"), dialog_row_len); row++; x509_issuer = X509_get_issuer_name(cert); for (unsigned int u = 0; u < mutt_array_size(part); u++) { snprintf(menu->dialog[row++], dialog_row_len, " %s", x509_get_part(x509_issuer, part[u])); } row++; snprintf(menu->dialog[row++], dialog_row_len, "%s", _("This certificate is valid")); snprintf(menu->dialog[row++], dialog_row_len, _(" from %s"), asn1time_to_string(X509_getm_notBefore(cert))); snprintf(menu->dialog[row++], dialog_row_len, _(" to %s"), asn1time_to_string(X509_getm_notAfter(cert))); row++; buf[0] = '\0'; x509_fingerprint(buf, sizeof(buf), cert, EVP_sha1); snprintf(menu->dialog[row++], dialog_row_len, _("SHA1 Fingerprint: %s"), buf); buf[0] = '\0'; buf[40] = '\0'; /* Ensure the second printed line is null terminated */ x509_fingerprint(buf, sizeof(buf), cert, EVP_sha256); buf[39] = '\0'; /* Divide into two lines of output */ snprintf(menu->dialog[row++], dialog_row_len, "%s%s", _("SHA256 Fingerprint: "), buf); snprintf(menu->dialog[row++], dialog_row_len, "%*s%s", (int) mutt_str_strlen(_("SHA256 Fingerprint: ")), "", buf + 40); snprintf(title, sizeof(title), _("SSL Certificate check (certificate %zu of %zu in chain)"), len - idx, len); menu->title = title; /* The leaf/host certificate can't be skipped. */ #ifdef HAVE_SSL_PARTIAL_CHAIN if ((idx != 0) && C_SslVerifyPartialChains) ALLOW_SKIP = 1; #endif /* Inside ssl_verify_callback(), this function is guarded by a call to * check_certificate_by_digest(). This means if check_certificate_expiration() is * true, then check_certificate_file() must be false. Therefore we don't need * to also scan the certificate file here. */ allow_always = allow_always && C_CertificateFile && check_certificate_expiration(cert, true); /* L10N: These four letters correspond to the choices in the next four strings: (r)eject, accept (o)nce, (a)ccept always, (s)kip. These prompts are the interactive certificate confirmation prompts for an OpenSSL connection. */ menu->keys = _("roas"); if (allow_always) { if (ALLOW_SKIP) menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always, (s)kip"); else menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); } else { if (ALLOW_SKIP) menu->prompt = _("(r)eject, accept (o)nce, (s)kip"); else menu->prompt = _("(r)eject, accept (o)nce"); } helpstr[0] = '\0'; mutt_make_help(buf, sizeof(buf), _("Exit "), MENU_GENERIC, OP_EXIT); mutt_str_strcat(helpstr, sizeof(helpstr), buf); mutt_make_help(buf, sizeof(buf), _("Help"), MENU_GENERIC, OP_HELP); mutt_str_strcat(helpstr, sizeof(helpstr), buf); menu->help = helpstr; done = 0; OptIgnoreMacroEvents = true; while (done == 0) { switch (mutt_menu_loop(menu)) { case -1: /* abort */ case OP_MAX + 1: /* reject */ case OP_EXIT: done = 1; break; case OP_MAX + 3: /* accept always */ if (!allow_always) break; done = 0; fp = fopen(C_CertificateFile, "a"); if (fp) { if (PEM_write_X509(fp, cert)) done = 1; mutt_file_fclose(&fp); } if (done == 0) { mutt_error(_("Warning: Couldn't save certificate")); } else { mutt_message(_("Certificate saved")); mutt_sleep(0); } /* fallthrough */ case OP_MAX + 2: /* accept once */ done = 2; SSL_set_ex_data(ssl, SkipModeExDataIndex, NULL); ssl_cache_trusted_cert(cert); break; case OP_MAX + 4: /* skip */ if (!ALLOW_SKIP) break; done = 2; SSL_set_ex_data(ssl, SkipModeExDataIndex, &SkipModeExDataIndex); break; } } OptIgnoreMacroEvents = false; mutt_menu_pop_current(menu); mutt_menu_destroy(&menu); mutt_debug(LL_DEBUG2, "done=%d\n", done); return done == 2; }