Conf *conf = (Conf *)data;
if (event == EVENT_REFRESH) {
- dlg_filesel_set(ctrl, dlg, *conf_get_filename(conf, key));
+ dlg_filesel_set(ctrl, dlg, conf_get_filename(conf, key));
} else if (event == EVENT_VALCHANGE) {
- Filename filename;
- dlg_filesel_get(ctrl, dlg, &filename);
- conf_set_filename(conf, key, &filename);
- /* If Filenames ever become dynamic, free this one. */
+ Filename *filename = dlg_filesel_get(ctrl, dlg);
+ conf_set_filename(conf, key, filename);
+ filename_free(filename);
}
}
if (event == EVENT_REFRESH) {
int i;
- static const struct { char *s; int c; } ciphers[] = {
+ static const struct { const char *s; int c; } ciphers[] = {
+ { "ChaCha20 (SSH-2 only)", CIPHER_CHACHA20 },
{ "3DES", CIPHER_3DES },
{ "Blowfish", CIPHER_BLOWFISH },
{ "DES", CIPHER_DES },
for (i = 0; i < CIPHER_MAX; i++) {
int c = conf_get_int_int(conf, CONF_ssh_cipherlist, i);
int j;
- char *cstr = NULL;
+ const char *cstr = NULL;
for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
if (ciphers[j].c == c) {
cstr = ciphers[j].s;
if (event == EVENT_REFRESH) {
int i;
- static const struct { char *s; int k; } kexes[] = {
+ static const struct { const char *s; int k; } kexes[] = {
{ "Diffie-Hellman group 1", KEX_DHGROUP1 },
{ "Diffie-Hellman group 14", KEX_DHGROUP14 },
{ "Diffie-Hellman group exchange", KEX_DHGEX },
{ "RSA-based key exchange", KEX_RSA },
+ { "ECDH key exchange", KEX_ECDH },
{ "-- warn below here --", KEX_WARN }
};
for (i = 0; i < KEX_MAX; i++) {
int k = conf_get_int_int(conf, CONF_ssh_kexlist, i);
int j;
- char *kstr = NULL;
+ const char *kstr = NULL;
for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
if (kexes[j].k == k) {
kstr = kexes[j].s;
}
}
+static void hklist_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Conf *conf = (Conf *)data;
+ if (event == EVENT_REFRESH) {
+ int i;
+
+ static const struct { const char *s; int k; } hks[] = {
+ { "Ed25519", HK_ED25519 },
+ { "ECDSA", HK_ECDSA },
+ { "DSA", HK_DSA },
+ { "RSA", HK_RSA },
+ { "-- warn below here --", HK_WARN }
+ };
+
+ /* Set up the "host key preference" box. */
+ /* (hklist assumed to contain all algorithms) */
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; i < HK_MAX; i++) {
+ int k = conf_get_int_int(conf, CONF_ssh_hklist, i);
+ int j;
+ const char *kstr = NULL;
+ for (j = 0; j < lenof(hks); j++) {
+ if (hks[j].k == k) {
+ kstr = hks[j].s;
+ break;
+ }
+ }
+ dlg_listbox_addwithid(ctrl, dlg, kstr, k);
+ }
+ dlg_update_done(ctrl, dlg);
+
+ } else if (event == EVENT_VALCHANGE) {
+ int i;
+
+ /* Update array to match the list box. */
+ for (i=0; i < HK_MAX; i++)
+ conf_set_int_int(conf, CONF_ssh_hklist, i,
+ dlg_listbox_getid(ctrl, dlg, i));
+ }
+}
+
static void printerbox_handler(union control *ctrl, void *dlg,
void *data, int event)
{
if (event == EVENT_REFRESH) {
int nprinters, i;
printer_enum *pe;
- char *printer;
+ const char *printer;
dlg_update_start(ctrl, dlg);
/*
{
Conf *conf = (Conf *)data;
if (event == EVENT_REFRESH) {
+ /*
+ * We must fetch the previously configured value from the Conf
+ * before we start modifying the drop-down list, otherwise the
+ * spurious SELCHANGE we trigger in the process will overwrite
+ * the value we wanted to keep.
+ */
+ int oldconf = conf_get_int(conf, ctrl->listbox.context.i);
dlg_update_start(ctrl, dlg);
dlg_listbox_clear(ctrl, dlg);
dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
- switch (conf_get_int(conf, ctrl->listbox.context.i)) {
+ switch (oldconf) {
case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
}
}
-#define SAVEDSESSION_LEN 2048
-
struct sessionsaver_data {
union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
union control *okbutton, *cancelbutton;
struct sesslist sesslist;
int midsession;
+ char *savedsession; /* the current contents of ssd->editbox */
};
+static void sessionsaver_data_free(void *ssdv)
+{
+ struct sessionsaver_data *ssd = (struct sessionsaver_data *)ssdv;
+ get_sesslist(&ssd->sesslist, FALSE);
+ sfree(ssd->savedsession);
+ sfree(ssd);
+}
+
/*
* Helper function to load the session selected in the list box, if
* any, as this is done in more than one place below. Returns 0 for
* failure.
*/
static int load_selected_session(struct sessionsaver_data *ssd,
- char *savedsession,
void *dlg, Conf *conf, int *maybe_launch)
{
int i = dlg_listbox_index(ssd->listbox, dlg);
}
isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
load_settings(ssd->sesslist.sessions[i], conf);
- if (!isdef) {
- strncpy(savedsession, ssd->sesslist.sessions[i],
- SAVEDSESSION_LEN);
- savedsession[SAVEDSESSION_LEN-1] = '\0';
- if (maybe_launch)
- *maybe_launch = TRUE;
- } else {
- savedsession[0] = '\0';
- if (maybe_launch)
- *maybe_launch = FALSE;
- }
+ sfree(ssd->savedsession);
+ ssd->savedsession = dupstr(isdef ? "" : ssd->sesslist.sessions[i]);
+ if (maybe_launch)
+ *maybe_launch = !isdef;
dlg_refresh(NULL, dlg);
/* Restore the selection, which might have been clobbered by
* changing the value of the edit box. */
Conf *conf = (Conf *)data;
struct sessionsaver_data *ssd =
(struct sessionsaver_data *)ctrl->generic.context.p;
- char *savedsession;
-
- /*
- * The first time we're called in a new dialog, we must
- * allocate space to store the current contents of the saved
- * session edit box (since it must persist even when we switch
- * panels, but is not part of the Conf).
- *
- * FIXME: this is disgusting, and we'd do much better to have
- * the persistent storage be dynamically allocated and get rid
- * of the arbitrary limit SAVEDSESSION_LEN. To do that would
- * require a means of making sure the memory gets freed at the
- * appropriate moment.
- */
- if (!ssd->editbox) {
- savedsession = NULL;
- } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
- savedsession = (char *)
- dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
- savedsession[0] = '\0';
- } else {
- savedsession = dlg_get_privdata(ssd->editbox, dlg);
- }
if (event == EVENT_REFRESH) {
if (ctrl == ssd->editbox) {
- dlg_editbox_set(ctrl, dlg, savedsession);
+ dlg_editbox_set(ctrl, dlg, ssd->savedsession);
} else if (ctrl == ssd->listbox) {
int i;
dlg_update_start(ctrl, dlg);
} else if (event == EVENT_VALCHANGE) {
int top, bottom, halfway, i;
if (ctrl == ssd->editbox) {
- char *tmp = dlg_editbox_get(ctrl, dlg);
- strncpy(savedsession, tmp, SAVEDSESSION_LEN);
- sfree(tmp);
+ sfree(ssd->savedsession);
+ ssd->savedsession = dlg_editbox_get(ctrl, dlg);
top = ssd->sesslist.nsessions;
bottom = -1;
while (top-bottom > 1) {
halfway = (top+bottom)/2;
- i = strcmp(savedsession, ssd->sesslist.sessions[halfway]);
+ i = strcmp(ssd->savedsession, ssd->sesslist.sessions[halfway]);
if (i <= 0 ) {
top = halfway;
} else {
* double-click on the list box _and_ that session
* contains a hostname.
*/
- if (load_selected_session(ssd, savedsession, dlg, conf, &mbl) &&
+ if (load_selected_session(ssd, dlg, conf, &mbl) &&
(mbl && ctrl == ssd->listbox && conf_launchable(conf))) {
dlg_end(dlg, 1); /* it's all over, and succeeded */
}
} else if (ctrl == ssd->savebutton) {
- int isdef = !strcmp(savedsession, "Default Settings");
- if (!savedsession[0]) {
+ int isdef = !strcmp(ssd->savedsession, "Default Settings");
+ if (!ssd->savedsession[0]) {
int i = dlg_listbox_index(ssd->listbox, dlg);
if (i < 0) {
dlg_beep(dlg);
return;
}
isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
- if (!isdef) {
- strncpy(savedsession, ssd->sesslist.sessions[i],
- SAVEDSESSION_LEN);
- savedsession[SAVEDSESSION_LEN-1] = '\0';
- } else {
- savedsession[0] = '\0';
- }
+ sfree(ssd->savedsession);
+ ssd->savedsession = dupstr(isdef ? "" :
+ ssd->sesslist.sessions[i]);
}
{
- char *errmsg = save_settings(savedsession, conf);
+ char *errmsg = save_settings(ssd->savedsession, conf);
if (errmsg) {
dlg_error_msg(dlg, errmsg);
sfree(errmsg);
!conf_launchable(conf)) {
Conf *conf2 = conf_new();
int mbl = FALSE;
- if (!load_selected_session(ssd, savedsession, dlg,
- conf2, &mbl)) {
+ if (!load_selected_session(ssd, dlg, conf2, &mbl)) {
dlg_beep(dlg);
conf_free(conf2);
return;
} else {
clear = FALSE;
r = conf_get_int_int(conf, CONF_colours, i*3+0);
- g = conf_get_int_int(conf, CONF_colours, i*3+0);
- b = conf_get_int_int(conf, CONF_colours, i*3+0);
+ g = conf_get_int_int(conf, CONF_colours, i*3+1);
+ b = conf_get_int_int(conf, CONF_colours, i*3+2);
}
update = TRUE;
}
*/
if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
conf_set_int_int(conf, CONF_colours, i*3+0, r);
- conf_set_int_int(conf, CONF_colours, i*3+0, g);
- conf_set_int_int(conf, CONF_colours, i*3+0, b);
+ conf_set_int_int(conf, CONF_colours, i*3+1, g);
+ conf_set_int_int(conf, CONF_colours, i*3+2, b);
clear = FALSE;
update = TRUE;
}
val != NULL;
val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
char *p;
- if (!strcmp(val, "D"))
- p = dupprintf("D%s\t", key+1);
- else
+ if (!strcmp(val, "D")) {
+ char *L;
+ /*
+ * A dynamic forwarding is stored as L12345=D or
+ * 6L12345=D (since it's mutually exclusive with
+ * L12345=anything else), but displayed as D12345
+ * to match the fiction that 'Local', 'Remote' and
+ * 'Dynamic' are three distinct modes and also to
+ * align with OpenSSH's command line option syntax
+ * that people will already be used to. So, for
+ * display purposes, find the L in the key string
+ * and turn it into a D.
+ */
+ p = dupprintf("%s\t", key);
+ L = strchr(p, 'L');
+ if (L) *L = 'D';
+ } else
p = dupprintf("%s\t%s", key, val);
dlg_listbox_add(ctrl, dlg, p);
sfree(p);
}
} else if (event == EVENT_ACTION) {
if (ctrl == pfd->addbutton) {
- char *family, *type, *src, *key, *val;
- int i, whichbutton;
+ const char *family, *type;
+ char *src, *key, *val;
+ int whichbutton;
- i = 0;
#ifndef NO_IPV6
whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
if (whichbutton == 1)
else if (whichbutton == 2)
family = "6";
else
- family = "";
#endif
+ family = "";
whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
if (whichbutton == 0)
}
if (*type != 'D') {
val = dlg_editbox_get(pfd->destbox, dlg);
- if (!*val || !strchr(val, ':')) {
+ if (!*val || !host_strchr(val, ':')) {
dlg_error_msg(dlg,
"You need to specify a destination address\n"
"in the form \"host.name:port\"");
if (i < 0) {
dlg_beep(dlg);
} else {
- char *key, *val, *p;
+ char *key, *p;
+ const char *val;
key = conf_get_str_nthstrkey(conf, CONF_portfwd, i);
if (key) {
}
}
+struct manual_hostkey_data {
+ union control *addbutton, *rembutton, *listbox, *keybox;
+};
+
+static void manual_hostkey_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Conf *conf = (Conf *)data;
+ struct manual_hostkey_data *mh =
+ (struct manual_hostkey_data *)ctrl->generic.context.p;
+
+ if (event == EVENT_REFRESH) {
+ if (ctrl == mh->listbox) {
+ char *key, *val;
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
+ NULL, &key);
+ val != NULL;
+ val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
+ key, &key)) {
+ dlg_listbox_add(ctrl, dlg, key);
+ }
+ dlg_update_done(ctrl, dlg);
+ }
+ } else if (event == EVENT_ACTION) {
+ if (ctrl == mh->addbutton) {
+ char *key;
+
+ key = dlg_editbox_get(mh->keybox, dlg);
+ if (!*key) {
+ dlg_error_msg(dlg, "You need to specify a host key or "
+ "fingerprint");
+ sfree(key);
+ return;
+ }
+
+ if (!validate_manual_hostkey(key)) {
+ dlg_error_msg(dlg, "Host key is not in a valid format");
+ } else if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys,
+ key)) {
+ dlg_error_msg(dlg, "Specified host key is already listed");
+ } else {
+ conf_set_str_str(conf, CONF_ssh_manual_hostkeys, key, "");
+ }
+
+ sfree(key);
+ dlg_refresh(mh->listbox, dlg);
+ } else if (ctrl == mh->rembutton) {
+ int i = dlg_listbox_index(mh->listbox, dlg);
+ if (i < 0) {
+ dlg_beep(dlg);
+ } else {
+ char *key;
+
+ key = conf_get_str_nthstrkey(conf, CONF_ssh_manual_hostkeys, i);
+ if (key) {
+ dlg_editbox_set(mh->keybox, dlg, key);
+ /* And delete it */
+ conf_del_str_str(conf, CONF_ssh_manual_hostkeys, key);
+ }
+ }
+ dlg_refresh(mh->listbox, dlg);
+ }
+ }
+}
+
void setup_config_box(struct controlbox *b, int midsession,
int protocol, int protcfginfo)
{
struct ttymodes_data *td;
struct environ_data *ed;
struct portfwd_data *pfd;
+ struct manual_hostkey_data *mh;
union control *c;
char *str;
ssd = (struct sessionsaver_data *)
- ctrl_alloc(b, sizeof(struct sessionsaver_data));
+ ctrl_alloc_with_free(b, sizeof(struct sessionsaver_data),
+ sessionsaver_data_free);
memset(ssd, 0, sizeof(*ssd));
+ ssd->savedsession = dupstr("");
ssd->midsession = midsession;
/*
ctrl_columns(s, 1, 100);
s = ctrl_getset(b, "Session", "otheropts", NULL);
- c = ctrl_radiobuttons(s, "Close window on exit:", 'x', 4,
- HELPCTX(session_coe),
- conf_radiobutton_handler,
- I(CONF_close_on_exit),
- "Always", I(FORCE_ON),
- "Never", I(FORCE_OFF),
- "Only on clean exit", I(AUTO), NULL);
+ ctrl_radiobuttons(s, "Close window on exit:", 'x', 4,
+ HELPCTX(session_coe),
+ conf_radiobutton_handler,
+ I(CONF_close_on_exit),
+ "Always", I(FORCE_ON),
+ "Never", I(FORCE_OFF),
+ "Only on clean exit", I(AUTO), NULL);
/*
* The Session/Logging panel.
* logging can sensibly be available.
*/
{
- char *sshlogname, *sshrawlogname;
+ const char *sshlogname, *sshrawlogname;
if ((midsession && protocol == PROT_SSH) ||
(!midsession && backend_from_proto(PROT_SSH))) {
sshlogname = "SSH packets";
HELPCTX(logging_filename),
conf_filesel_handler, I(CONF_logfilename));
ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
- " &T for time, and &H for host name)",
+ " &T for time, &H for host name, and &P for port number)",
HELPCTX(logging_filename));
ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
HELPCTX(logging_exists),
HELPCTX(features_retitle),
conf_checkbox_handler,
I(CONF_no_remote_wintitle));
+ ctrl_checkbox(s, "Disable remote-controlled clearing of scrollback", 'e',
+ HELPCTX(features_clearscroll),
+ conf_checkbox_handler,
+ I(CONF_no_remote_clearscroll));
ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
HELPCTX(features_qtitle),
conf_radiobutton_handler,
ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
HELPCTX(colours_xterm256), conf_checkbox_handler,
I(CONF_xterm_256_colour));
- ctrl_checkbox(s, "Bolded text is a different colour", 'b',
- HELPCTX(colours_bold),
- conf_checkbox_handler, I(CONF_bold_colour));
+ ctrl_radiobuttons(s, "Indicate bolded text by changing:", 'b', 3,
+ HELPCTX(colours_bold),
+ conf_radiobutton_handler, I(CONF_bold_style),
+ "The font", I(1),
+ "The colour", I(2),
+ "Both", I(3),
+ NULL);
str = dupprintf("Adjust the precise colours %s displays", appname);
s = ctrl_getset(b, "Window/Colours", "adjust", str);
#endif
{
- char *label = backend_from_proto(PROT_SSH) ?
+ const char *label = backend_from_proto(PROT_SSH) ?
"Logical name of remote host (e.g. for SSH key lookup):" :
"Logical name of remote host:";
s = ctrl_getset(b, "Connection", "identity",
HELPCTX(proxy_command),
conf_editbox_handler,
I(CONF_proxy_telnet_command), I(1));
+
+ ctrl_radiobuttons(s, "Print proxy diagnostics "
+ "in the terminal window", 'r', 5,
+ HELPCTX(proxy_main),
+ conf_radiobutton_handler,
+ I(CONF_proxy_log_to_term),
+ "No", I(FORCE_OFF),
+ "Yes", I(FORCE_ON),
+ "Only until session starts", I(AUTO), NULL);
}
/*
ctrl_settitle(b, "Connection/SSH",
"Options controlling SSH connections");
- if (midsession && protcfginfo == 1) {
+ /* SSH-1 or connection-sharing downstream */
+ if (midsession && (protcfginfo == 1 || protcfginfo == -1)) {
s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
"session; it is only here so that sub-panels of it can "
I(CONF_ssh_no_shell));
}
- if (!midsession || protcfginfo != 1) {
+ if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
ctrl_checkbox(s, "Enable compression", 'e',
I(CONF_compression));
}
+ if (!midsession) {
+ s = ctrl_getset(b, "Connection/SSH", "sharing", "Sharing an SSH connection between PuTTY tools");
+
+ ctrl_checkbox(s, "Share SSH connections if possible", 's',
+ HELPCTX(ssh_share),
+ conf_checkbox_handler,
+ I(CONF_ssh_connection_sharing));
+
+ ctrl_text(s, "Permitted roles in a shared connection:",
+ HELPCTX(ssh_share));
+ ctrl_checkbox(s, "Upstream (connecting to the real server)", 'u',
+ HELPCTX(ssh_share),
+ conf_checkbox_handler,
+ I(CONF_ssh_connection_sharing_upstream));
+ ctrl_checkbox(s, "Downstream (connecting to the upstream PuTTY)", 'd',
+ HELPCTX(ssh_share),
+ conf_checkbox_handler,
+ I(CONF_ssh_connection_sharing_downstream));
+ }
+
if (!midsession) {
s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
- ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
+ ctrl_radiobuttons(s, "SSH protocol version:", NO_SHORTCUT, 2,
HELPCTX(ssh_protocol),
conf_radiobutton_handler,
I(CONF_sshprot),
- "1 only", 'l', I(0),
- "1", '1', I(1),
- "2", '2', I(2),
- "2 only", 'y', I(3), NULL);
- }
-
- if (!midsession || protcfginfo != 1) {
- s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
- c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
- HELPCTX(ssh_ciphers),
- cipherlist_handler, P(NULL));
- c->listbox.height = 6;
-
- ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
- HELPCTX(ssh_ciphers),
- conf_checkbox_handler,
- I(CONF_ssh2_des_cbc));
+ "2", '2', I(3),
+ "1 (INSECURE)", '1', I(0), NULL);
}
/*
* The Connection/SSH/Kex panel. (Owing to repeat key
- * exchange, this is all meaningful in mid-session _if_
- * we're using SSH-2 or haven't decided yet.)
+ * exchange, much of this is meaningful in mid-session _if_
+ * we're using SSH-2 and are not a connection-sharing
+ * downstream, or haven't decided yet.)
*/
- if (protcfginfo != 1) {
+ if (protcfginfo != 1 && protcfginfo != -1) {
ctrl_settitle(b, "Connection/SSH/Kex",
"Options controlling SSH key exchange");
HELPCTX(ssh_kex_repeat));
}
+ /*
+ * The 'Connection/SSH/Host keys' panel.
+ */
+ if (protcfginfo != 1 && protcfginfo != -1) {
+ ctrl_settitle(b, "Connection/SSH/Host keys",
+ "Options controlling SSH host keys");
+
+ s = ctrl_getset(b, "Connection/SSH/Host keys", "main",
+ "Host key algorithm preference");
+ c = ctrl_draglist(s, "Algorithm selection policy:", 's',
+ HELPCTX(ssh_hklist),
+ hklist_handler, P(NULL));
+ c->listbox.height = 5;
+ }
+
+ /*
+ * Manual host key configuration is irrelevant mid-session,
+ * as we enforce that the host key for rekeys is the
+ * same as that used at the start of the session.
+ */
+ if (!midsession) {
+ s = ctrl_getset(b, "Connection/SSH/Host keys", "hostkeys",
+ "Manually configure host keys for this connection");
+
+ ctrl_columns(s, 2, 75, 25);
+ c = ctrl_text(s, "Host keys or fingerprints to accept:",
+ HELPCTX(ssh_kex_manual_hostkeys));
+ c->generic.column = 0;
+ /* You want to select from the list, _then_ hit Remove. So
+ * tab order should be that way round. */
+ mh = (struct manual_hostkey_data *)
+ ctrl_alloc(b,sizeof(struct manual_hostkey_data));
+ mh->rembutton = ctrl_pushbutton(s, "Remove", 'r',
+ HELPCTX(ssh_kex_manual_hostkeys),
+ manual_hostkey_handler, P(mh));
+ mh->rembutton->generic.column = 1;
+ mh->rembutton->generic.tabdelay = 1;
+ mh->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
+ HELPCTX(ssh_kex_manual_hostkeys),
+ manual_hostkey_handler, P(mh));
+ /* This list box can't be very tall, because there's not
+ * much room in the pane on Windows at least. This makes
+ * it become really unhelpful if a horizontal scrollbar
+ * appears, so we suppress that. */
+ mh->listbox->listbox.height = 2;
+ mh->listbox->listbox.hscroll = FALSE;
+ ctrl_tabdelay(s, mh->rembutton);
+ mh->keybox = ctrl_editbox(s, "Key", 'k', 80,
+ HELPCTX(ssh_kex_manual_hostkeys),
+ manual_hostkey_handler, P(mh), P(NULL));
+ mh->keybox->generic.column = 0;
+ mh->addbutton = ctrl_pushbutton(s, "Add key", 'y',
+ HELPCTX(ssh_kex_manual_hostkeys),
+ manual_hostkey_handler, P(mh));
+ mh->addbutton->generic.column = 1;
+ ctrl_columns(s, 1, 100);
+ }
+
+ if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
+ /*
+ * The Connection/SSH/Cipher panel.
+ */
+ ctrl_settitle(b, "Connection/SSH/Cipher",
+ "Options controlling SSH encryption");
+
+ s = ctrl_getset(b, "Connection/SSH/Cipher",
+ "encryption", "Encryption options");
+ c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
+ HELPCTX(ssh_ciphers),
+ cipherlist_handler, P(NULL));
+ c->listbox.height = 6;
+
+ ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
+ HELPCTX(ssh_ciphers),
+ conf_checkbox_handler,
+ I(CONF_ssh2_des_cbc));
+ }
+
if (!midsession) {
/*
"Options controlling SSH authentication");
s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
- ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
- HELPCTX(ssh_auth_bypass),
- conf_checkbox_handler,
- I(CONF_ssh_no_userauth));
ctrl_checkbox(s, "Display pre-authentication banner (SSH-2 only)",
'd', HELPCTX(ssh_auth_banner),
conf_checkbox_handler,
I(CONF_ssh_show_banner));
+ ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
+ HELPCTX(ssh_auth_bypass),
+ conf_checkbox_handler,
+ I(CONF_ssh_no_userauth));
s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
"Authentication methods");
if (!midsession) {
/*
- * The Connection/SSH/Bugs panel.
+ * The Connection/SSH/Bugs panels.
*/
ctrl_settitle(b, "Connection/SSH/Bugs",
"Workarounds for SSH server bugs");
s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
"Detection of known bugs in SSH servers");
- ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
- HELPCTX(ssh_bugs_ignore1),
- sshbug_handler, I(CONF_sshbug_ignore1));
- ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
- HELPCTX(ssh_bugs_plainpw1),
- sshbug_handler, I(CONF_sshbug_plainpw1));
- ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
- HELPCTX(ssh_bugs_rsa1),
- sshbug_handler, I(CONF_sshbug_rsa1));
ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
HELPCTX(ssh_bugs_ignore2),
sshbug_handler, I(CONF_sshbug_ignore2));
- ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
- HELPCTX(ssh_bugs_hmac2),
- sshbug_handler, I(CONF_sshbug_hmac2));
- ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
- HELPCTX(ssh_bugs_derivekey2),
- sshbug_handler, I(CONF_sshbug_derivekey2));
- ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
- HELPCTX(ssh_bugs_rsapad2),
- sshbug_handler, I(CONF_sshbug_rsapad2));
- ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
- HELPCTX(ssh_bugs_pksessid2),
- sshbug_handler, I(CONF_sshbug_pksessid2));
ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
HELPCTX(ssh_bugs_rekey2),
sshbug_handler, I(CONF_sshbug_rekey2));
+ ctrl_droplist(s, "Chokes on PuTTY's SSH-2 'winadj' requests", 'j',
+ 20, HELPCTX(ssh_bugs_winadj),
+ sshbug_handler, I(CONF_sshbug_winadj));
+ ctrl_droplist(s, "Replies to requests on closed channels", 'q', 20,
+ HELPCTX(ssh_bugs_chanreq),
+ sshbug_handler, I(CONF_sshbug_chanreq));
ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
HELPCTX(ssh_bugs_maxpkt2),
sshbug_handler, I(CONF_sshbug_maxpkt2));
+
+ ctrl_settitle(b, "Connection/SSH/More bugs",
+ "Further workarounds for SSH server bugs");
+
+ s = ctrl_getset(b, "Connection/SSH/More bugs", "main",
+ "Detection of known bugs in SSH servers");
+ ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
+ HELPCTX(ssh_bugs_rsapad2),
+ sshbug_handler, I(CONF_sshbug_rsapad2));
+ ctrl_droplist(s, "Only supports pre-RFC4419 SSH-2 DH GEX", 'd', 20,
+ HELPCTX(ssh_bugs_oldgex2),
+ sshbug_handler, I(CONF_sshbug_oldgex2));
+ ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
+ HELPCTX(ssh_bugs_hmac2),
+ sshbug_handler, I(CONF_sshbug_hmac2));
+ ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
+ HELPCTX(ssh_bugs_pksessid2),
+ sshbug_handler, I(CONF_sshbug_pksessid2));
+ ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
+ HELPCTX(ssh_bugs_derivekey2),
+ sshbug_handler, I(CONF_sshbug_derivekey2));
+ ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
+ HELPCTX(ssh_bugs_ignore1),
+ sshbug_handler, I(CONF_sshbug_ignore1));
+ ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
+ HELPCTX(ssh_bugs_plainpw1),
+ sshbug_handler, I(CONF_sshbug_plainpw1));
+ ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
+ HELPCTX(ssh_bugs_rsa1),
+ sshbug_handler, I(CONF_sshbug_rsa1));
}
}
}