commit - fef9de8ff7030ff5eecba8cbb6a6def8b5bce9c8
commit + 288fd238ab2466e7fc9d8d11e7dd92363326a66f
blob - f1d91bbbe7efedd85f36c3a3127776239806b287
blob + 82e0f91bff2cf8e134c77bcea58c00500c6e79e6
--- ChangeLog
+++ ChangeLog
2021-04-25 Omar Polo <op@omarpolo.com>
+ * telescope.c (handle_check_cert_user_choice): allow saving the new certificate after mismatch
+
* fs.c (load_certs): don't crash on invalid lines in known_hosts
* hash.c (telescope_lookup_tofu): save certificates per (host, port) tuple, not only per-host
blob - 3959ee825b9e66fc3f65c56fdece058323e8080d
blob + 2b96509fdd0337da41b701583d79bb641267d74e
--- fs.c
+++ fs.c
static void handle_quit(struct imsg*, size_t);
static void handle_bookmark_page(struct imsg*, size_t);
static void handle_save_cert(struct imsg*, size_t);
+static void handle_update_cert(struct imsg*, size_t);
static void handle_session_start(struct imsg*, size_t);
static void handle_session_tab(struct imsg*, size_t);
static void handle_session_end(struct imsg*, size_t);
static FILE *session;
static char bookmark_file[PATH_MAX];
-static char known_hosts_file[PATH_MAX];
+static char known_hosts_file[PATH_MAX], known_hosts_tmp[PATH_MAX];
static char session_file[PATH_MAX];
static imsg_handlerfn *handlers[] = {
[IMSG_QUIT] = handle_quit,
[IMSG_BOOKMARK_PAGE] = handle_bookmark_page,
[IMSG_SAVE_CERT] = handle_save_cert,
+ [IMSG_UPDATE_CERT] = handle_update_cert,
[IMSG_SESSION_START] = handle_session_start,
[IMSG_SESSION_TAB] = handle_session_tab,
[IMSG_SESSION_END] = handle_session_end,
res = 0;
end:
imsg_compose(ibuf, IMSG_SAVE_CERT_OK, imsg->hdr.peerid, 0, -1,
+ &res, sizeof(res));
+ imsg_flush(ibuf);
+}
+
+static void
+handle_update_cert(struct imsg *imsg, size_t datalen)
+{
+ FILE *tmp, *f;
+ struct tofu_entry entry;
+ char sfn[PATH_MAX], *line = NULL, *t;
+ size_t l, linesize = 0;
+ ssize_t linelen;
+ int fd, e, res = 0;
+
+ if (datalen != sizeof(entry))
+ die();
+ memcpy(&entry, imsg->data, datalen);
+
+ strlcpy(sfn, known_hosts_tmp, sizeof(sfn));
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (tmp = fdopen(fd, "w")) == NULL) {
+ if (fd != -1) {
+ unlink(sfn);
+ close(fd);
+ }
+ res = 0;
+ goto end;
+ }
+
+ if ((f = fopen(known_hosts_file, "r")) == NULL) {
+ unlink(sfn);
+ fclose(tmp);
+ res = 0;
+ goto end;
+ }
+
+ l = strlen(entry.domain);
+ while ((linelen = getline(&line, &linesize, f)) != -1) {
+ if ((t = strstr(line, entry.domain)) != NULL &&
+ (line[l] == ' ' || line[l] == '\t'))
+ continue;
+ /* line has a trailing \n */
+ fprintf(tmp, "%s", line);
+ }
+ fprintf(tmp, "%s %s %d\n", entry.domain, entry.hash, entry.verified);
+
+ free(line);
+ e = ferror(tmp);
+
+ fclose(tmp);
+ fclose(f);
+
+ if (e) {
+ unlink(sfn);
+ res = 0;
+ goto end;
+ }
+
+ res = rename(sfn, known_hosts_file) != -1;
+
+end:
+ imsg_compose(ibuf, IMSG_UPDATE_CERT_OK, imsg->hdr.peerid, 0, -1,
&res, sizeof(res));
imsg_flush(ibuf);
}
strlcpy(known_hosts_file, getenv("HOME"), sizeof(known_hosts_file));
strlcat(known_hosts_file, "/.telescope/known_hosts", sizeof(known_hosts_file));
+ strlcpy(known_hosts_tmp, getenv("HOME"), sizeof(known_hosts_tmp));
+ strlcat(known_hosts_tmp, "/.telescope/known_hosts.tmp.XXXXXXXXXX",
+ sizeof(known_hosts_file));
+
strlcpy(session_file, getenv("HOME"), sizeof(session_file));
strlcat(session_file, "/.telescope/session", sizeof(session_file));
blob - 1dc54d50a6a4ae71a414eb217d9d8799d0b34fde
blob + 01b9fe34f05109df256fc7d27e1a1b48d74f00bb
--- telescope.c
+++ telescope.c
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_imsg_got_code(struct imsg*, size_t);
static void handle_imsg_got_meta(struct imsg*, size_t);
static void handle_imsg_buf(struct imsg*, size_t);
static void handle_imsg_eof(struct imsg*, size_t);
static void handle_imsg_bookmark_ok(struct imsg*, size_t);
static void handle_imsg_save_cert_ok(struct imsg*, size_t);
+static void handle_imsg_update_cert_ok(struct imsg *, size_t);
static void handle_dispatch_imsg(int, short, void*);
static void load_page_from_str(struct tab*, const char*);
static void do_load_url(struct tab*, const char*);
[IMSG_EOF] = handle_imsg_eof,
[IMSG_BOOKMARK_OK] = handle_imsg_bookmark_ok,
[IMSG_SAVE_CERT_OK] = handle_imsg_save_cert_ok,
+ [IMSG_UPDATE_CERT_OK] = handle_imsg_update_cert_ok,
};
static struct ohash certs;
} else {
tab->trust = TS_UNTRUSTED;
load_page_from_str(tab, "# Certificate mismatch\n");
+ if ((tab->cert = strdup(hash)) == NULL)
+ die();
ui_yornp("Certificate mismatch. Proceed?",
handle_check_cert_user_choice, tab->id);
}
static void
handle_check_cert_user_choice(int accept, unsigned int tabid)
{
+ struct tab *tab;
+
+ tab = tab_by_id(tabid);
+
imsg_compose(netibuf, IMSG_CERT_STATUS, tabid, 0, -1,
&accept, sizeof(accept));
imsg_flush(netibuf);
+
+ if (accept)
+ ui_yornp("Save the new certificate?",
+ handle_maybe_save_new_cert, tabid);
+ else {
+ free(tab->cert);
+ tab->cert = NULL;
+ }
}
+static void
+handle_maybe_save_new_cert(int accept, unsigned int tabid)
+{
+ struct tab *tab;
+ struct tofu_entry *e;
+
+ tab = tab_by_id(tabid);
+
+ if (!accept)
+ goto end;
+
+ if ((e = calloc(1, sizeof(e))) == NULL)
+ die();
+
+ strlcpy(e->domain, tab->uri.host, sizeof(e->domain));
+ if (*tab->uri.port != '\0' && strcmp(tab->uri.port, "1965")) {
+ strlcat(e->domain, ":", sizeof(e->domain));
+ strlcat(e->domain, tab->uri.port, sizeof(e->domain));
+ }
+ strlcpy(e->hash, tab->cert, sizeof(e->hash));
+ imsg_compose(fsibuf, IMSG_UPDATE_CERT, 0, 0, -1, e, sizeof(*e));
+ imsg_flush(fsibuf);
+
+ tofu_update(&certs, e);
+
+ tab->trust = TS_TRUSTED;
+
+end:
+ free(tab->cert);
+ tab->cert = NULL;
+}
+
static inline int
normalize_code(int n)
{
if (res != 0)
ui_notify("Failed to save the cert for: %s",
strerror(res));
+}
+
+static void
+handle_imsg_update_cert_ok(struct imsg *imsg, size_t datalen)
+{
+ int res;
+
+ if (datalen != sizeof(res))
+ die();
+ memcpy(&res, imsg->data, datalen);
+ if (!res)
+ ui_notify("Failed to update the certificate");
}
static void
blob - d972e44d1820f75c484a8f39a511b7e3e3997bf0
blob + 3a5b568ee0673fb93a01be0ae82ff2ec4f6b75af
--- telescope.h
+++ telescope.h
IMSG_BOOKMARK_OK,
IMSG_SAVE_CERT,
IMSG_SAVE_CERT_OK,
+ IMSG_UPDATE_CERT,
+ IMSG_UPDATE_CERT_OK,
IMSG_SESSION_START,
IMSG_SESSION_TAB,
uint32_t id;
uint32_t flags;
+ char *cert;
enum trust_state trust;
struct phos_uri uri;
struct histhead hist;
void tofu_init(struct ohash*, unsigned int, ptrdiff_t);
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*);
/* ui.c */
unsigned int tab_new_id(void);
blob - 1814b4ea5d3302c0cbd2f818d003bc8c72d64710
blob + b474a99d2639bb8390a3b0ec64e782783a93d344
--- tofu.c
+++ tofu.c
slot = ohash_qlookup(h, e->domain);
ohash_insert(h, slot, e);
}
+
+void
+tofu_update(struct ohash *h, struct tofu_entry *e)
+{
+ struct tofu_entry *t;
+
+ if ((t = tofu_lookup(h, e->domain, NULL)) == NULL)
+ tofu_add(h, e);
+ else {
+ strlcpy(t->hash, e->hash, sizeof(t->hash));
+ t->verified = e->verified;
+ free(e);
+ }
+}