mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 01:18:00 +00:00
Move host CA config box out into its own source file.
In the course of polishing up this dialog box, I'm going to want it to actually do cryptographic things (such as checking validity of a public key blob and printing its fingerprint), which means it will need to link against SSH utility functions. So I've moved the dialog-box setup and handling code out of config.c into a new file in the ssh subdirectory and in the ssh library, where those facilities will be conveniently available. This also means that dialog-box setup code _won't_ be linked into PuTTYtel or pterm (on either platform), so I've added a stub source file to provide its entry-point function in those tools. Also, provided a const bool to indicate whether that dialog is available, which we use to decide whether to recognise that command-line option.
This commit is contained in:
parent
694d5184b7
commit
4fcb3bbe81
361
config.c
361
config.c
@ -3316,364 +3316,3 @@ void setup_config_box(struct controlbox *b, bool midsession,
|
||||
I(CONF_supdup_scroll));
|
||||
}
|
||||
}
|
||||
|
||||
struct ca_state {
|
||||
dlgcontrol *ca_name_edit;
|
||||
dlgcontrol *ca_reclist;
|
||||
dlgcontrol *ca_pubkey_edit;
|
||||
dlgcontrol *ca_wclist;
|
||||
dlgcontrol *ca_wc_edit;
|
||||
char *name, *pubkey, *wc;
|
||||
tree234 *ca_names; /* stores plain 'char *' */
|
||||
tree234 *host_wcs; /* stores plain 'char *' */
|
||||
};
|
||||
|
||||
static int ca_name_compare(void *av, void *bv)
|
||||
{
|
||||
return strcmp((const char *)av, (const char *)bv);
|
||||
}
|
||||
|
||||
static inline void clear_string_tree(tree234 *t)
|
||||
{
|
||||
char *p;
|
||||
while ((p = delpos234(t, 0)) != NULL)
|
||||
sfree(p);
|
||||
}
|
||||
|
||||
static void ca_state_free(void *vctx)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)vctx;
|
||||
clear_string_tree(st->ca_names);
|
||||
freetree234(st->ca_names);
|
||||
clear_string_tree(st->host_wcs);
|
||||
freetree234(st->host_wcs);
|
||||
sfree(st->name);
|
||||
sfree(st->wc);
|
||||
sfree(st);
|
||||
}
|
||||
|
||||
static void ca_refresh_name_list(struct ca_state *st)
|
||||
{
|
||||
clear_string_tree(st->ca_names);
|
||||
|
||||
host_ca_enum *hce = enum_host_ca_start();
|
||||
if (hce) {
|
||||
strbuf *namebuf = strbuf_new();
|
||||
|
||||
while (strbuf_clear(namebuf), enum_host_ca_next(hce, namebuf)) {
|
||||
char *name = dupstr(namebuf->s);
|
||||
char *added = add234(st->ca_names, name);
|
||||
/* Just imaginable that concurrent filesystem access might
|
||||
* cause a repetition; avoid leaking memory if so */
|
||||
if (added != name)
|
||||
sfree(name);
|
||||
}
|
||||
|
||||
strbuf_free(namebuf);
|
||||
enum_host_ca_finish(hce);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_load_selected_record(struct ca_state *st, dlgparam *dp)
|
||||
{
|
||||
int i = dlg_listbox_index(st->ca_reclist, dp);
|
||||
if (i < 0) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
const char *name = index234(st->ca_names, i);
|
||||
if (!name) { /* in case the list box and the tree got out of sync */
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
host_ca *hca = host_ca_load(name);
|
||||
if (!hca) {
|
||||
char *msg = dupprintf("Unable to load host CA record '%s'", name);
|
||||
dlg_error_msg(dp, msg);
|
||||
sfree(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
sfree(st->name);
|
||||
st->name = dupstr(hca->name);
|
||||
|
||||
sfree(st->pubkey);
|
||||
st->pubkey = strbuf_to_str(
|
||||
base64_encode_sb(ptrlen_from_strbuf(hca->ca_public_key), 0));
|
||||
|
||||
clear_string_tree(st->host_wcs);
|
||||
for (size_t i = 0; i < hca->n_hostname_wildcards; i++) {
|
||||
char *name = dupstr(hca->hostname_wildcards[i]);
|
||||
char *added = add234(st->host_wcs, name);
|
||||
if (added != name)
|
||||
sfree(name); /* de-duplicate, just in case */
|
||||
}
|
||||
|
||||
host_ca_free(hca);
|
||||
|
||||
dlg_refresh(st->ca_name_edit, dp);
|
||||
dlg_refresh(st->ca_pubkey_edit, dp);
|
||||
dlg_refresh(st->ca_wclist, dp);
|
||||
}
|
||||
|
||||
static void ca_ok_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
if (event == EVENT_ACTION)
|
||||
dlg_end(dp, 0);
|
||||
}
|
||||
|
||||
static void ca_name_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_editbox_set(ctrl, dp, st->name);
|
||||
} else if (event == EVENT_VALCHANGE) {
|
||||
sfree(st->name);
|
||||
st->name = dlg_editbox_get(ctrl, dp);
|
||||
|
||||
/*
|
||||
* Try to auto-select the typed name in the list.
|
||||
*/
|
||||
int index;
|
||||
if (!findrelpos234(st->ca_names, st->name, NULL, REL234_GE, &index))
|
||||
index = count234(st->ca_names) - 1;
|
||||
if (index >= 0)
|
||||
dlg_listbox_select(st->ca_reclist, dp, index);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_reclist_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_update_start(ctrl, dp);
|
||||
dlg_listbox_clear(ctrl, dp);
|
||||
const char *name;
|
||||
for (int i = 0; (name = index234(st->ca_names, i)) != NULL; i++)
|
||||
dlg_listbox_add(ctrl, dp, name);
|
||||
dlg_update_done(ctrl, dp);
|
||||
} else if (event == EVENT_ACTION) {
|
||||
/* Double-clicking a session loads it */
|
||||
ca_load_selected_record(st, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_load_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
ca_load_selected_record(st, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_save_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
host_ca *hca = snew(host_ca);
|
||||
memset(hca, 0, sizeof(*hca));
|
||||
hca->name = dupstr(st->name);
|
||||
hca->ca_public_key = base64_decode_sb(ptrlen_from_asciz(st->pubkey));
|
||||
hca->n_hostname_wildcards = count234(st->host_wcs);
|
||||
hca->hostname_wildcards = snewn(hca->n_hostname_wildcards, char *);
|
||||
for (size_t i = 0; i < hca->n_hostname_wildcards; i++)
|
||||
hca->hostname_wildcards[i] = dupstr(index234(st->host_wcs, i));
|
||||
char *error = host_ca_save(hca);
|
||||
host_ca_free(hca);
|
||||
|
||||
if (error) {
|
||||
dlg_error_msg(dp, error);
|
||||
sfree(error);
|
||||
} else {
|
||||
ca_refresh_name_list(st);
|
||||
dlg_refresh(st->ca_reclist, dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_delete_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
int i = dlg_listbox_index(st->ca_reclist, dp);
|
||||
if (i < 0) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
const char *name = index234(st->ca_names, i);
|
||||
if (!name) { /* in case the list box and the tree got out of sync */
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
|
||||
char *error = host_ca_delete(name);
|
||||
if (error) {
|
||||
dlg_error_msg(dp, error);
|
||||
sfree(error);
|
||||
} else {
|
||||
ca_refresh_name_list(st);
|
||||
dlg_refresh(st->ca_reclist, dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_pubkey_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_editbox_set(ctrl, dp, st->pubkey);
|
||||
} else if (event == EVENT_VALCHANGE) {
|
||||
sfree(st->pubkey);
|
||||
st->pubkey = dlg_editbox_get(ctrl, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wclist_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_update_start(ctrl, dp);
|
||||
dlg_listbox_clear(ctrl, dp);
|
||||
const char *name;
|
||||
for (int i = 0; (name = index234(st->host_wcs, i)) != NULL; i++)
|
||||
dlg_listbox_add(ctrl, dp, name);
|
||||
dlg_update_done(ctrl, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wc_edit_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_editbox_set(ctrl, dp, st->wc);
|
||||
} else if (event == EVENT_VALCHANGE) {
|
||||
sfree(st->wc);
|
||||
st->wc = dlg_editbox_get(ctrl, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wc_add_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
if (!st->wc) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (add234(st->host_wcs, st->wc) == st->wc) {
|
||||
dlg_refresh(st->ca_wclist, dp);
|
||||
} else {
|
||||
sfree(st->wc);
|
||||
}
|
||||
|
||||
st->wc = dupstr("");
|
||||
dlg_refresh(st->ca_wc_edit, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wc_rem_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
int i = dlg_listbox_index(st->ca_wclist, dp);
|
||||
if (i < 0) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
char *wc = delpos234(st->host_wcs, i);
|
||||
if (!wc) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
|
||||
sfree(st->wc);
|
||||
st->wc = wc;
|
||||
dlg_refresh(st->ca_wclist, dp);
|
||||
dlg_refresh(st->ca_wc_edit, dp);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_ca_config_box(struct controlbox *b)
|
||||
{
|
||||
struct controlset *s;
|
||||
dlgcontrol *c;
|
||||
|
||||
/* Internal state for manipulating the host CA system */
|
||||
struct ca_state *st = (struct ca_state *)ctrl_alloc_with_free(
|
||||
b, sizeof(struct ca_state), ca_state_free);
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->name = dupstr("");
|
||||
st->pubkey = dupstr("");
|
||||
st->ca_names = newtree234(ca_name_compare);
|
||||
st->host_wcs = newtree234(ca_name_compare);
|
||||
ca_refresh_name_list(st);
|
||||
|
||||
/* Action area, with the Done button in it */
|
||||
s = ctrl_getset(b, "", "", "");
|
||||
ctrl_columns(s, 5, 20, 20, 20, 20, 20);
|
||||
c = ctrl_pushbutton(s, "Done", 'o', HELPCTX(no_help),
|
||||
ca_ok_handler, P(st));
|
||||
c->button.isdefault = true;
|
||||
c->column = 4;
|
||||
|
||||
/* Load/save box, as similar as possible to the main saved sessions one */
|
||||
s = ctrl_getset(b, "Main", "loadsave",
|
||||
"Load, save or delete a host CA record");
|
||||
ctrl_columns(s, 2, 75, 25);
|
||||
c = ctrl_editbox(s, "Name for this CA (shown in log messages)",
|
||||
'n', 100, HELPCTX(no_help),
|
||||
ca_name_handler, P(st), P(NULL));
|
||||
c->column = 0;
|
||||
st->ca_name_edit = c;
|
||||
/* Reset columns so that the buttons are alongside the list, rather
|
||||
* than alongside that edit box. */
|
||||
ctrl_columns(s, 1, 100);
|
||||
ctrl_columns(s, 2, 75, 25);
|
||||
c = ctrl_listbox(s, NULL, NO_SHORTCUT, HELPCTX(no_help),
|
||||
ca_reclist_handler, P(st));
|
||||
c->column = 0;
|
||||
c->listbox.height = 6;
|
||||
st->ca_reclist = c;
|
||||
c = ctrl_pushbutton(s, "Load", 'l', HELPCTX(no_help),
|
||||
ca_load_handler, P(st));
|
||||
c->column = 1;
|
||||
c = ctrl_pushbutton(s, "Save", 'v', HELPCTX(no_help),
|
||||
ca_save_handler, P(st));
|
||||
c->column = 1;
|
||||
c = ctrl_pushbutton(s, "Delete", 'd', HELPCTX(no_help),
|
||||
ca_delete_handler, P(st));
|
||||
c->column = 1;
|
||||
|
||||
/* Box containing the details of a specific CA record */
|
||||
s = ctrl_getset(b, "Main", "details", "Details of a host CA record");
|
||||
c = ctrl_editbox(s, "Public key of certification authority", 'k', 100,
|
||||
HELPCTX(no_help), ca_pubkey_handler, P(st), P(NULL));
|
||||
st->ca_pubkey_edit = c;
|
||||
c = ctrl_listbox(s, "Hostname patterns this key is trusted to certify",
|
||||
NO_SHORTCUT, HELPCTX(no_help), ca_wclist_handler, P(st));
|
||||
c->listbox.height = 3;
|
||||
st->ca_wclist = c;
|
||||
ctrl_columns(s, 3, 70, 15, 15);
|
||||
c = ctrl_editbox(s, "Hostname pattern to add", 'h', 100,
|
||||
HELPCTX(no_help), ca_wc_edit_handler, P(st), P(NULL));
|
||||
c->column = 0;
|
||||
st->ca_wc_edit = c;
|
||||
c = ctrl_pushbutton(s, "Add", NO_SHORTCUT, HELPCTX(no_help),
|
||||
ca_wc_add_handler, P(st));
|
||||
c->column = 1;
|
||||
c = ctrl_pushbutton(s, "Remove", NO_SHORTCUT, HELPCTX(no_help),
|
||||
ca_wc_rem_handler, P(st));
|
||||
c->column = 2;
|
||||
}
|
||||
|
1
putty.h
1
putty.h
@ -2589,6 +2589,7 @@ void setup_ca_config_box(struct controlbox *b);
|
||||
|
||||
/* Platforms provide this to be called from config.c */
|
||||
void show_ca_config_box(dlgparam *dlg);
|
||||
extern const bool has_ca_config_box; /* false if, e.g., we're PuTTYtel */
|
||||
|
||||
/* Visible outside config.c so that platforms can use it to recognise
|
||||
* the proxy type control */
|
||||
|
@ -2,6 +2,7 @@ add_library(sshcommon OBJECT
|
||||
bpp1.c
|
||||
bpp2.c
|
||||
bpp-bare.c
|
||||
ca-config.c
|
||||
censor1.c
|
||||
censor2.c
|
||||
common.c
|
||||
|
372
ssh/ca-config.c
Normal file
372
ssh/ca-config.c
Normal file
@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Define and handle the configuration dialog box for SSH host CAs,
|
||||
* using the same portable dialog specification API as config.c.
|
||||
*/
|
||||
|
||||
#include "putty.h"
|
||||
#include "dialog.h"
|
||||
#include "storage.h"
|
||||
#include "tree234.h"
|
||||
|
||||
const bool has_ca_config_box = true;
|
||||
|
||||
struct ca_state {
|
||||
dlgcontrol *ca_name_edit;
|
||||
dlgcontrol *ca_reclist;
|
||||
dlgcontrol *ca_pubkey_edit;
|
||||
dlgcontrol *ca_wclist;
|
||||
dlgcontrol *ca_wc_edit;
|
||||
char *name, *pubkey, *wc;
|
||||
tree234 *ca_names; /* stores plain 'char *' */
|
||||
tree234 *host_wcs; /* stores plain 'char *' */
|
||||
};
|
||||
|
||||
static int ca_name_compare(void *av, void *bv)
|
||||
{
|
||||
return strcmp((const char *)av, (const char *)bv);
|
||||
}
|
||||
|
||||
static inline void clear_string_tree(tree234 *t)
|
||||
{
|
||||
char *p;
|
||||
while ((p = delpos234(t, 0)) != NULL)
|
||||
sfree(p);
|
||||
}
|
||||
|
||||
static void ca_state_free(void *vctx)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)vctx;
|
||||
clear_string_tree(st->ca_names);
|
||||
freetree234(st->ca_names);
|
||||
clear_string_tree(st->host_wcs);
|
||||
freetree234(st->host_wcs);
|
||||
sfree(st->name);
|
||||
sfree(st->wc);
|
||||
sfree(st);
|
||||
}
|
||||
|
||||
static void ca_refresh_name_list(struct ca_state *st)
|
||||
{
|
||||
clear_string_tree(st->ca_names);
|
||||
|
||||
host_ca_enum *hce = enum_host_ca_start();
|
||||
if (hce) {
|
||||
strbuf *namebuf = strbuf_new();
|
||||
|
||||
while (strbuf_clear(namebuf), enum_host_ca_next(hce, namebuf)) {
|
||||
char *name = dupstr(namebuf->s);
|
||||
char *added = add234(st->ca_names, name);
|
||||
/* Just imaginable that concurrent filesystem access might
|
||||
* cause a repetition; avoid leaking memory if so */
|
||||
if (added != name)
|
||||
sfree(name);
|
||||
}
|
||||
|
||||
strbuf_free(namebuf);
|
||||
enum_host_ca_finish(hce);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_load_selected_record(struct ca_state *st, dlgparam *dp)
|
||||
{
|
||||
int i = dlg_listbox_index(st->ca_reclist, dp);
|
||||
if (i < 0) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
const char *name = index234(st->ca_names, i);
|
||||
if (!name) { /* in case the list box and the tree got out of sync */
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
host_ca *hca = host_ca_load(name);
|
||||
if (!hca) {
|
||||
char *msg = dupprintf("Unable to load host CA record '%s'", name);
|
||||
dlg_error_msg(dp, msg);
|
||||
sfree(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
sfree(st->name);
|
||||
st->name = dupstr(hca->name);
|
||||
|
||||
sfree(st->pubkey);
|
||||
st->pubkey = strbuf_to_str(
|
||||
base64_encode_sb(ptrlen_from_strbuf(hca->ca_public_key), 0));
|
||||
|
||||
clear_string_tree(st->host_wcs);
|
||||
for (size_t i = 0; i < hca->n_hostname_wildcards; i++) {
|
||||
char *name = dupstr(hca->hostname_wildcards[i]);
|
||||
char *added = add234(st->host_wcs, name);
|
||||
if (added != name)
|
||||
sfree(name); /* de-duplicate, just in case */
|
||||
}
|
||||
|
||||
host_ca_free(hca);
|
||||
|
||||
dlg_refresh(st->ca_name_edit, dp);
|
||||
dlg_refresh(st->ca_pubkey_edit, dp);
|
||||
dlg_refresh(st->ca_wclist, dp);
|
||||
}
|
||||
|
||||
static void ca_ok_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
if (event == EVENT_ACTION)
|
||||
dlg_end(dp, 0);
|
||||
}
|
||||
|
||||
static void ca_name_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_editbox_set(ctrl, dp, st->name);
|
||||
} else if (event == EVENT_VALCHANGE) {
|
||||
sfree(st->name);
|
||||
st->name = dlg_editbox_get(ctrl, dp);
|
||||
|
||||
/*
|
||||
* Try to auto-select the typed name in the list.
|
||||
*/
|
||||
int index;
|
||||
if (!findrelpos234(st->ca_names, st->name, NULL, REL234_GE, &index))
|
||||
index = count234(st->ca_names) - 1;
|
||||
if (index >= 0)
|
||||
dlg_listbox_select(st->ca_reclist, dp, index);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_reclist_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_update_start(ctrl, dp);
|
||||
dlg_listbox_clear(ctrl, dp);
|
||||
const char *name;
|
||||
for (int i = 0; (name = index234(st->ca_names, i)) != NULL; i++)
|
||||
dlg_listbox_add(ctrl, dp, name);
|
||||
dlg_update_done(ctrl, dp);
|
||||
} else if (event == EVENT_ACTION) {
|
||||
/* Double-clicking a session loads it */
|
||||
ca_load_selected_record(st, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_load_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
ca_load_selected_record(st, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_save_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
host_ca *hca = snew(host_ca);
|
||||
memset(hca, 0, sizeof(*hca));
|
||||
hca->name = dupstr(st->name);
|
||||
hca->ca_public_key = base64_decode_sb(ptrlen_from_asciz(st->pubkey));
|
||||
hca->n_hostname_wildcards = count234(st->host_wcs);
|
||||
hca->hostname_wildcards = snewn(hca->n_hostname_wildcards, char *);
|
||||
for (size_t i = 0; i < hca->n_hostname_wildcards; i++)
|
||||
hca->hostname_wildcards[i] = dupstr(index234(st->host_wcs, i));
|
||||
char *error = host_ca_save(hca);
|
||||
host_ca_free(hca);
|
||||
|
||||
if (error) {
|
||||
dlg_error_msg(dp, error);
|
||||
sfree(error);
|
||||
} else {
|
||||
ca_refresh_name_list(st);
|
||||
dlg_refresh(st->ca_reclist, dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_delete_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
int i = dlg_listbox_index(st->ca_reclist, dp);
|
||||
if (i < 0) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
const char *name = index234(st->ca_names, i);
|
||||
if (!name) { /* in case the list box and the tree got out of sync */
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
|
||||
char *error = host_ca_delete(name);
|
||||
if (error) {
|
||||
dlg_error_msg(dp, error);
|
||||
sfree(error);
|
||||
} else {
|
||||
ca_refresh_name_list(st);
|
||||
dlg_refresh(st->ca_reclist, dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_pubkey_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_editbox_set(ctrl, dp, st->pubkey);
|
||||
} else if (event == EVENT_VALCHANGE) {
|
||||
sfree(st->pubkey);
|
||||
st->pubkey = dlg_editbox_get(ctrl, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wclist_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_update_start(ctrl, dp);
|
||||
dlg_listbox_clear(ctrl, dp);
|
||||
const char *name;
|
||||
for (int i = 0; (name = index234(st->host_wcs, i)) != NULL; i++)
|
||||
dlg_listbox_add(ctrl, dp, name);
|
||||
dlg_update_done(ctrl, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wc_edit_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_REFRESH) {
|
||||
dlg_editbox_set(ctrl, dp, st->wc);
|
||||
} else if (event == EVENT_VALCHANGE) {
|
||||
sfree(st->wc);
|
||||
st->wc = dlg_editbox_get(ctrl, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wc_add_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
if (!st->wc) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (add234(st->host_wcs, st->wc) == st->wc) {
|
||||
dlg_refresh(st->ca_wclist, dp);
|
||||
} else {
|
||||
sfree(st->wc);
|
||||
}
|
||||
|
||||
st->wc = dupstr("");
|
||||
dlg_refresh(st->ca_wc_edit, dp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_wc_rem_handler(dlgcontrol *ctrl, dlgparam *dp,
|
||||
void *data, int event)
|
||||
{
|
||||
struct ca_state *st = (struct ca_state *)ctrl->context.p;
|
||||
if (event == EVENT_ACTION) {
|
||||
int i = dlg_listbox_index(st->ca_wclist, dp);
|
||||
if (i < 0) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
char *wc = delpos234(st->host_wcs, i);
|
||||
if (!wc) {
|
||||
dlg_beep(dp);
|
||||
return;
|
||||
}
|
||||
|
||||
sfree(st->wc);
|
||||
st->wc = wc;
|
||||
dlg_refresh(st->ca_wclist, dp);
|
||||
dlg_refresh(st->ca_wc_edit, dp);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_ca_config_box(struct controlbox *b)
|
||||
{
|
||||
struct controlset *s;
|
||||
dlgcontrol *c;
|
||||
|
||||
/* Internal state for manipulating the host CA system */
|
||||
struct ca_state *st = (struct ca_state *)ctrl_alloc_with_free(
|
||||
b, sizeof(struct ca_state), ca_state_free);
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->name = dupstr("");
|
||||
st->pubkey = dupstr("");
|
||||
st->ca_names = newtree234(ca_name_compare);
|
||||
st->host_wcs = newtree234(ca_name_compare);
|
||||
ca_refresh_name_list(st);
|
||||
|
||||
/* Action area, with the Done button in it */
|
||||
s = ctrl_getset(b, "", "", "");
|
||||
ctrl_columns(s, 5, 20, 20, 20, 20, 20);
|
||||
c = ctrl_pushbutton(s, "Done", 'o', HELPCTX(no_help),
|
||||
ca_ok_handler, P(st));
|
||||
c->button.isdefault = true;
|
||||
c->column = 4;
|
||||
|
||||
/* Load/save box, as similar as possible to the main saved sessions one */
|
||||
s = ctrl_getset(b, "Main", "loadsave",
|
||||
"Load, save or delete a host CA record");
|
||||
ctrl_columns(s, 2, 75, 25);
|
||||
c = ctrl_editbox(s, "Name for this CA (shown in log messages)",
|
||||
'n', 100, HELPCTX(no_help),
|
||||
ca_name_handler, P(st), P(NULL));
|
||||
c->column = 0;
|
||||
st->ca_name_edit = c;
|
||||
/* Reset columns so that the buttons are alongside the list, rather
|
||||
* than alongside that edit box. */
|
||||
ctrl_columns(s, 1, 100);
|
||||
ctrl_columns(s, 2, 75, 25);
|
||||
c = ctrl_listbox(s, NULL, NO_SHORTCUT, HELPCTX(no_help),
|
||||
ca_reclist_handler, P(st));
|
||||
c->column = 0;
|
||||
c->listbox.height = 6;
|
||||
st->ca_reclist = c;
|
||||
c = ctrl_pushbutton(s, "Load", 'l', HELPCTX(no_help),
|
||||
ca_load_handler, P(st));
|
||||
c->column = 1;
|
||||
c = ctrl_pushbutton(s, "Save", 'v', HELPCTX(no_help),
|
||||
ca_save_handler, P(st));
|
||||
c->column = 1;
|
||||
c = ctrl_pushbutton(s, "Delete", 'd', HELPCTX(no_help),
|
||||
ca_delete_handler, P(st));
|
||||
c->column = 1;
|
||||
|
||||
/* Box containing the details of a specific CA record */
|
||||
s = ctrl_getset(b, "Main", "details", "Details of a host CA record");
|
||||
c = ctrl_editbox(s, "Public key of certification authority", 'k', 100,
|
||||
HELPCTX(no_help), ca_pubkey_handler, P(st), P(NULL));
|
||||
st->ca_pubkey_edit = c;
|
||||
c = ctrl_listbox(s, "Hostname patterns this key is trusted to certify",
|
||||
NO_SHORTCUT, HELPCTX(no_help), ca_wclist_handler, P(st));
|
||||
c->listbox.height = 3;
|
||||
st->ca_wclist = c;
|
||||
ctrl_columns(s, 3, 70, 15, 15);
|
||||
c = ctrl_editbox(s, "Hostname pattern to add", 'h', 100,
|
||||
HELPCTX(no_help), ca_wc_edit_handler, P(st), P(NULL));
|
||||
c->column = 0;
|
||||
st->ca_wc_edit = c;
|
||||
c = ctrl_pushbutton(s, "Add", NO_SHORTCUT, HELPCTX(no_help),
|
||||
ca_wc_add_handler, P(st));
|
||||
c->column = 1;
|
||||
c = ctrl_pushbutton(s, "Remove", NO_SHORTCUT, HELPCTX(no_help),
|
||||
ca_wc_rem_handler, P(st));
|
||||
c->column = 2;
|
||||
}
|
14
stubs/no-ca-config.c
Normal file
14
stubs/no-ca-config.c
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Stub version of setup_ca_config_box, for tools that don't have SSH
|
||||
* code linked in.
|
||||
*/
|
||||
|
||||
#include "putty.h"
|
||||
#include "dialog.h"
|
||||
|
||||
const bool has_ca_config_box = false;
|
||||
|
||||
void setup_ca_config_box(struct controlbox *b)
|
||||
{
|
||||
unreachable("should never call setup_ca_config_box in this application");
|
||||
}
|
@ -134,6 +134,7 @@ if(GTK_FOUND)
|
||||
pterm.c
|
||||
main-gtk-simple.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/nogss.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/no-ca-config.c
|
||||
${CMAKE_SOURCE_DIR}/proxy/nosshproxy.c
|
||||
pty.c)
|
||||
be_list(pterm pterm)
|
||||
@ -148,6 +149,7 @@ if(GTK_FOUND)
|
||||
main-gtk-application.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/nocmdline.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/nogss.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/no-ca-config.c
|
||||
${CMAKE_SOURCE_DIR}/proxy/nosshproxy.c
|
||||
pty.c)
|
||||
be_list(ptermapp pterm)
|
||||
@ -184,6 +186,7 @@ if(GTK_FOUND)
|
||||
putty.c
|
||||
main-gtk-simple.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/nogss.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/no-ca-config.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/norand.c
|
||||
${CMAKE_SOURCE_DIR}/proxy/nocproxy.c
|
||||
${CMAKE_SOURCE_DIR}/proxy/nosshproxy.c)
|
||||
|
@ -532,8 +532,9 @@ bool do_cmdline(int argc, char **argv, bool do_everything, Conf *conf)
|
||||
pgp_fingerprints();
|
||||
exit(1);
|
||||
|
||||
} else if (!strcmp(p, "-host-ca") || !strcmp(p, "--host-ca") ||
|
||||
!strcmp(p, "-host_ca") || !strcmp(p, "--host_ca")) {
|
||||
} else if (has_ca_config_box &&
|
||||
(!strcmp(p, "-host-ca") || !strcmp(p, "--host-ca") ||
|
||||
!strcmp(p, "-host_ca") || !strcmp(p, "--host_ca"))) {
|
||||
show_ca_config_box_synchronously();
|
||||
exit(0);
|
||||
|
||||
|
@ -117,6 +117,7 @@ add_executable(puttytel
|
||||
putty.c
|
||||
help.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/nogss.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/no-ca-config.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/norand.c
|
||||
${CMAKE_SOURCE_DIR}/proxy/nocproxy.c
|
||||
${CMAKE_SOURCE_DIR}/proxy/nosshproxy.c
|
||||
@ -158,6 +159,7 @@ if(HAVE_CONPTY)
|
||||
help.c
|
||||
conpty.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/nogss.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/no-ca-config.c
|
||||
${CMAKE_SOURCE_DIR}/stubs/norand.c
|
||||
${CMAKE_SOURCE_DIR}/proxy/nosshproxy.c
|
||||
pterm.rc)
|
||||
|
@ -87,8 +87,9 @@ void gui_term_process_cmdline(Conf *conf, char *cmdline)
|
||||
} else if (!strcmp(p, "-pgpfp")) {
|
||||
pgp_fingerprints_msgbox(NULL);
|
||||
exit(1);
|
||||
} else if (!strcmp(p, "-host-ca") || !strcmp(p, "--host-ca") ||
|
||||
!strcmp(p, "-host_ca") || !strcmp(p, "--host_ca")) {
|
||||
} else if (has_ca_config_box &&
|
||||
(!strcmp(p, "-host-ca") || !strcmp(p, "--host-ca") ||
|
||||
!strcmp(p, "-host_ca") || !strcmp(p, "--host_ca"))) {
|
||||
show_ca_config_box(NULL);
|
||||
exit(0);
|
||||
} else if (!strcmp(p, "-demo-config-box")) {
|
||||
|
Loading…
Reference in New Issue
Block a user