commit a2fd3805b0807d0e85411613df26bd6dcaed01ce from: Omar Polo date: Tue Jul 06 17:44:54 2021 UTC fix two related bug Don't crash when there's a certificate mismatch and after saving the cert, before choosing to persist it, the page gets redirected; also, don't repeat the "Certificate mismatch" after the first yes, if there's a redirect. Now when the user accept a certificate, is treated as temporary saved for the whole session. commit - 9fedd923db07f03084a4efadf960020480d0db80 commit + a2fd3805b0807d0e85411613df26bd6dcaed01ce blob - e1e2f6100e6e2893f2f672f01835563a2a24528f blob + 38c23eb99a604a05c94508b2afdc5c1baf64681b --- ChangeLog +++ ChangeLog @@ -1,5 +1,7 @@ 2021-07-06 Omar Polo + * telescope.c (handle_check_cert_user_choice): fix two bug: don't crash when there's a certificate mismatch and after saving the cert, before choosing to persist it, the page gets redirected. Now when the user accept a certificate, is treated as temporary saved for the whole session. + * defaults.c (load_default_keys): bind M-prior/next (M-pageup/pagedown) to tab-previous and tab-next 2021-07-05 Omar Polo blob - 0242dd56c8199241ef26e40d82bcb0729755dd80 blob + 7c7f77a1f4e1fbe7110be914331bfaf7aea92664 --- telescope.c +++ telescope.c @@ -26,11 +26,11 @@ static void die(void) __attribute__((__noreturn__)); static struct tab *tab_by_id(uint32_t); static void handle_imsg_err(struct imsg*, size_t); static void handle_imsg_check_cert(struct imsg*, size_t); -static void handle_check_cert_user_choice(int, unsigned int); -static void handle_maybe_save_new_cert(int, unsigned int); +static void handle_check_cert_user_choice(int, struct tab *); +static void handle_maybe_save_new_cert(int, struct tab *); static void handle_imsg_got_code(struct imsg*, size_t); static void handle_imsg_got_meta(struct imsg*, size_t); -static void handle_maybe_save_page(int, unsigned int); +static void handle_maybe_save_page(int, struct tab *); static void handle_save_page_path(const char *, unsigned int); static void handle_imsg_file_opened(struct imsg*, size_t); static void handle_imsg_buf(struct imsg*, size_t); @@ -140,7 +140,13 @@ handle_imsg_check_cert(struct imsg *imsg, size_t datal tofu_res = !strcmp(hash, e->hash); if (tofu_res) { - tab->trust = e->verified ? TS_VERIFIED : TS_TRUSTED; + if (e->verified == -1) + tab->trust = TS_TEMP_TRUSTED; + else if (e->verified == 1) + tab->trust = TS_VERIFIED; + else + tab->trust = TS_TRUSTED; + imsg_compose(netibuf, IMSG_CERT_STATUS, imsg->hdr.peerid, 0, -1, &tofu_res, sizeof(tofu_res)); imsg_flush(netibuf); @@ -150,39 +156,42 @@ handle_imsg_check_cert(struct imsg *imsg, size_t datal if ((tab->cert = strdup(hash)) == NULL) die(); ui_yornp("Certificate mismatch. Proceed?", - handle_check_cert_user_choice, tab->id); + handle_check_cert_user_choice, tab); } } static void -handle_check_cert_user_choice(int accept, unsigned int tabid) +handle_check_cert_user_choice(int accept, struct tab *tab) { - struct tab *tab; - - tab = tab_by_id(tabid); - - imsg_compose(netibuf, IMSG_CERT_STATUS, tabid, 0, -1, + imsg_compose(netibuf, IMSG_CERT_STATUS, tab->id, 0, -1, &accept, sizeof(accept)); imsg_flush(netibuf); - if (accept) + if (accept) { + /* + * trust the certificate for this session only. If + * the page results in a redirect while we're asking + * the user to save, we'll end up with an invalid + * tabid (one request == one tab id) and crash. It + * also makes sense to save it for the current session + * if the user accepted it. + */ + tofu_temp_trust(&certs, tab->uri.host, tab->uri.port, tab->cert); + ui_yornp("Save the new certificate?", - handle_maybe_save_new_cert, tabid); - else { + handle_maybe_save_new_cert, tab); + } else { free(tab->cert); tab->cert = NULL; } } static void -handle_maybe_save_new_cert(int accept, unsigned int tabid) +handle_maybe_save_new_cert(int accept, struct tab *tab) { - struct tab *tab; struct tofu_entry *e; const char *host, *port; - tab = tab_by_id(tabid); - if (tab->proxy != NULL) { host = tab->proxy->host; port = tab->proxy->port; @@ -284,7 +293,7 @@ handle_imsg_got_meta(struct imsg *imsg, size_t datalen } else { load_page_from_str(tab, err_pages[UNKNOWN_TYPE_OR_CSET]); ui_yornp("Can't display page, wanna save?", - handle_maybe_save_page, tab->id); + handle_maybe_save_page, tab); } } else if (tab->code < 40) { /* 3x */ tab->redirect_count++; @@ -301,12 +310,12 @@ handle_imsg_got_meta(struct imsg *imsg, size_t datalen } static void -handle_maybe_save_page(int dosave, unsigned int tabid) +handle_maybe_save_page(int dosave, struct tab *tab) { if (dosave) - ui_read("Save to path", handle_save_page_path, tabid); + ui_read("Save to path", handle_save_page_path, tab->id); else - stop_tab(tab_by_id(tabid)); + stop_tab(tab); } static void blob - 0fa19093d9bea18e148c18178e4e1df77a2d3600 blob + 54c23576691a715aa722570bb81528d86e78b7ec --- telescope.h +++ telescope.h @@ -174,6 +174,7 @@ struct parser { enum trust_state { TS_UNKNOWN, TS_UNTRUSTED, + TS_TEMP_TRUSTED, TS_TRUSTED, TS_VERIFIED, }; @@ -383,6 +384,7 @@ void tofu_init(struct ohash*, unsigned int, ptrdiff struct tofu_entry *tofu_lookup(struct ohash*, const char*, const char*); void tofu_add(struct ohash*, struct tofu_entry*); void tofu_update(struct ohash*, struct tofu_entry*); +void tofu_temp_trust(struct ohash *, const char *, const char *, const char *); /* ui.c */ extern int body_lines; @@ -499,7 +501,7 @@ void ui_toggle_side_window(void); void ui_schedule_redraw(void); void ui_require_input(struct tab*, int); void ui_read(const char*, void(*)(const char*, unsigned int), unsigned int); -void ui_yornp(const char*, void (*)(int, unsigned int), unsigned int); +void ui_yornp(const char*, void (*)(int, struct tab *), struct tab *); void ui_end(void); /* utf.8 */ blob - b474a99d2639bb8390a3b0ec64e782783a93d344 blob + 6be7ec6fe0393108c660c9508e739cfe58beba2d --- tofu.c +++ tofu.c @@ -96,3 +96,23 @@ tofu_update(struct ohash *h, struct tofu_entry *e) free(e); } } + +void +tofu_temp_trust(struct ohash *h, const char *host, const char *port, + const char *hash) +{ + struct tofu_entry *e; + + if ((e = calloc(1, sizeof(*e))) == NULL) + abort(); + + strlcpy(e->domain, host, sizeof(e->domain)); + if (*port != '\0' && strcmp(port, "1965")) { + strlcat(e->domain, ":", sizeof(e->domain)); + strlcat(e->domain, port, sizeof(e->domain)); + } + strlcpy(e->hash, hash, sizeof(e->hash)); + e->verified = -1; + + tofu_update(h, e); +} blob - e8aa4f0a5a8bb9205f2f9116ec2fb1d8059df8f6 blob + c7b26c92c942ee917b5c9aa274f41084d0862f82 --- ui.c +++ ui.c @@ -104,8 +104,8 @@ static uint32_t tab_counter; static char keybuf[64]; -static void (*yornp_cb)(int, unsigned int); -static unsigned int yornp_data; +static void (*yornp_cb)(int, struct tab *); +static struct tab *yornp_data; static void (*read_cb)(const char*, unsigned int); static unsigned int read_data; @@ -906,6 +906,7 @@ trust_status_char(enum trust_state ts) switch (ts) { case TS_UNKNOWN: return 'u'; case TS_UNTRUSTED: return '!'; + case TS_TEMP_TRUSTED: return '!'; case TS_TRUSTED: return 'v'; case TS_VERIFIED: return 'V'; default: return 'X'; @@ -1479,8 +1480,8 @@ ui_require_input(struct tab *tab, int hide) } void -ui_yornp(const char *prompt, void (*fn)(int, unsigned int), - unsigned int data) +ui_yornp(const char *prompt, void (*fn)(int, struct tab *), + struct tab *data) { size_t len;