X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/9ad36e5fbb0bdbc6ddaf74b10333a0bfe2205600..b3d375b244187cd77f45dc013668e6273e133179:/config.c diff --git a/config.c b/config.c index 1e5f8da1..d689ede9 100644 --- a/config.c +++ b/config.c @@ -15,20 +15,6 @@ #define HOST_BOX_TITLE "Host Name (or IP address)" #define PORT_BOX_TITLE "Port" -/* - * Convenience function: determine whether this binary supports a - * given backend. - */ -static int have_backend(int protocol) -{ - struct backend_list *p = backends; - for (p = backends; p->name; p++) { - if (p->protocol == protocol) - return 1; - } - return 0; -} - static void config_host_handler(union control *ctrl, void *dlg, void *data, int event) { @@ -104,7 +90,7 @@ struct hostport { void config_protocolbuttons_handler(union control *ctrl, void *dlg, void *data, int event) { - int button, defport; + int button; Config *cfg = (Config *)data; struct hostport *hp = (struct hostport *)ctrl->radio.context.p; @@ -128,15 +114,20 @@ void config_protocolbuttons_handler(union control *ctrl, void *dlg, assert(button >= 0 && button < ctrl->radio.nbuttons); cfg->protocol = ctrl->radio.buttondata[button].i; if (oldproto != cfg->protocol) { - defport = -1; - switch (cfg->protocol) { - case PROT_SSH: defport = 22; break; - case PROT_TELNET: defport = 23; break; - case PROT_RLOGIN: defport = 513; break; - } - if (defport > 0 && cfg->port != defport) { - cfg->port = defport; - } + Backend *ob = backend_from_proto(oldproto); + Backend *nb = backend_from_proto(cfg->protocol); + assert(ob); + assert(nb); + /* Iff the user hasn't changed the port from the protocol + * default (if any), update it with the new protocol's + * default. + * (XXX: this isn't perfect; a default can become permanent + * by going via the serial backend. However, it helps with + * the common case of tabbing through the controls in order + * and setting a non-default port.) */ + if (cfg->port == ob->default_port && + cfg->port > 0 && nb->default_port > 0) + cfg->port = nb->default_port; } dlg_refresh(hp->host, dlg); dlg_refresh(hp->port, dlg); @@ -245,6 +236,33 @@ static void cipherlist_handler(union control *ctrl, void *dlg, } } +#ifndef NO_GSSAPI +static void gsslist_handler(union control *ctrl, void *dlg, + void *data, int event) +{ + Config *cfg = (Config *)data; + if (event == EVENT_REFRESH) { + int i; + + dlg_update_start(ctrl, dlg); + dlg_listbox_clear(ctrl, dlg); + for (i = 0; i < ngsslibs; i++) { + int id = cfg->ssh_gsslist[i]; + assert(id >= 0 && id < ngsslibs); + dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id); + } + dlg_update_done(ctrl, dlg); + + } else if (event == EVENT_VALCHANGE) { + int i; + + /* Update array to match the list box. */ + for (i=0; i < ngsslibs; i++) + cfg->ssh_gsslist[i] = dlg_listbox_getid(ctrl, dlg, i); + } +} +#endif + static void kexlist_handler(union control *ctrl, void *dlg, void *data, int event) { @@ -256,6 +274,7 @@ static void kexlist_handler(union control *ctrl, void *dlg, { "Diffie-Hellman group 1", KEX_DHGROUP1 }, { "Diffie-Hellman group 14", KEX_DHGROUP14 }, { "Diffie-Hellman group exchange", KEX_DHGEX }, + { "RSA-based key exchange", KEX_RSA }, { "-- warn below here --", KEX_WARN } }; @@ -325,14 +344,14 @@ static void codepage_handler(union control *ctrl, void *dlg, Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int i; - const char *cp; + const char *cp, *thiscp; dlg_update_start(ctrl, dlg); - strcpy(cfg->line_codepage, - cp_name(decode_codepage(cfg->line_codepage))); + thiscp = cp_name(decode_codepage(cfg->line_codepage)); dlg_listbox_clear(ctrl, dlg); for (i = 0; (cp = cp_enumerate(i)) != NULL; i++) dlg_listbox_add(ctrl, dlg, cp); - dlg_editbox_set(ctrl, dlg, cfg->line_codepage); + dlg_editbox_set(ctrl, dlg, thiscp); + strcpy(cfg->line_codepage, thiscp); dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { dlg_editbox_get(ctrl, dlg, cfg->line_codepage, @@ -383,7 +402,7 @@ struct sessionsaver_data { */ static int load_selected_session(struct sessionsaver_data *ssd, char *savedsession, - void *dlg, Config *cfg) + void *dlg, Config *cfg, int *maybe_launch) { int i = dlg_listbox_index(ssd->listbox, dlg); int isdef; @@ -392,13 +411,17 @@ static int load_selected_session(struct sessionsaver_data *ssd, return 0; } isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings"); - load_settings(ssd->sesslist.sessions[i], !isdef, cfg); + load_settings(ssd->sesslist.sessions[i], cfg); 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; } dlg_refresh(NULL, dlg); /* Restore the selection, which might have been clobbered by @@ -464,6 +487,7 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, dlg_listbox_select(ssd->listbox, dlg, top); } } else if (event == EVENT_ACTION) { + int mbl = FALSE; if (!ssd->midsession && (ctrl == ssd->listbox || (ssd->loadbutton && ctrl == ssd->loadbutton))) { @@ -474,8 +498,8 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, * double-click on the list box _and_ that session * contains a hostname. */ - if (load_selected_session(ssd, savedsession, dlg, cfg) && - (ctrl == ssd->listbox && cfg_launchable(cfg))) { + if (load_selected_session(ssd, savedsession, dlg, cfg, &mbl) && + (mbl && ctrl == ssd->listbox && cfg_launchable(cfg))) { dlg_end(dlg, 1); /* it's all over, and succeeded */ } } else if (ctrl == ssd->savebutton) { @@ -496,7 +520,7 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, } } { - char *errmsg = save_settings(savedsession, !isdef, cfg); + char *errmsg = save_settings(savedsession, cfg); if (errmsg) { dlg_error_msg(dlg, errmsg); sfree(errmsg); @@ -533,12 +557,14 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !cfg_launchable(cfg)) { Config cfg2; - if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) { + int mbl = FALSE; + if (!load_selected_session(ssd, savedsession, dlg, + &cfg2, &mbl)) { dlg_beep(dlg); return; } /* If at this point we have a valid session, go! */ - if (*cfg2.host) { + if (mbl && cfg_launchable(&cfg2)) { *cfg = cfg2; /* structure copy */ cfg->remote_cmd_ptr = NULL; dlg_end(dlg, 1); @@ -624,7 +650,7 @@ static void colour_handler(union control *ctrl, void *dlg, Config *cfg = (Config *)data; struct colour_data *cd = (struct colour_data *)ctrl->generic.context.p; - int update = FALSE, r, g, b; + int update = FALSE, clear = FALSE, r, g, b; if (event == EVENT_REFRESH) { if (ctrl == cd->listbox) { @@ -634,21 +660,21 @@ static void colour_handler(union control *ctrl, void *dlg, for (i = 0; i < lenof(colours); i++) dlg_listbox_add(ctrl, dlg, colours[i]); dlg_update_done(ctrl, dlg); - dlg_editbox_set(cd->redit, dlg, ""); - dlg_editbox_set(cd->gedit, dlg, ""); - dlg_editbox_set(cd->bedit, dlg, ""); + clear = TRUE; + update = TRUE; } } else if (event == EVENT_SELCHANGE) { if (ctrl == cd->listbox) { /* The user has selected a colour. Update the RGB text. */ int i = dlg_listbox_index(ctrl, dlg); if (i < 0) { - dlg_beep(dlg); - return; + clear = TRUE; + } else { + clear = FALSE; + r = cfg->colours[i][0]; + g = cfg->colours[i][1]; + b = cfg->colours[i][2]; } - r = cfg->colours[i][0]; - g = cfg->colours[i][1]; - b = cfg->colours[i][2]; update = TRUE; } } else if (event == EVENT_VALCHANGE) { @@ -701,16 +727,23 @@ static void colour_handler(union control *ctrl, void *dlg, cfg->colours[i][0] = r; cfg->colours[i][1] = g; cfg->colours[i][2] = b; + clear = FALSE; update = TRUE; } } } if (update) { - char buf[40]; - sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf); - sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf); - sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf); + if (clear) { + dlg_editbox_set(cd->redit, dlg, ""); + dlg_editbox_set(cd->gedit, dlg, ""); + dlg_editbox_set(cd->bedit, dlg, ""); + } else { + char buf[40]; + sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf); + sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf); + sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf); + } } } @@ -792,7 +825,29 @@ static void ttymodes_handler(union control *ctrl, void *dlg, char *p = cfg->ttymodes; int i = 0, len = lenof(cfg->ttymodes); while (*p) { + int multisel = dlg_listbox_index(td->listbox, dlg) < 0; if (dlg_listbox_issel(td->listbox, dlg, i)) { + if (!multisel) { + /* Populate controls with entry we're about to + * delete, for ease of editing. + * (If multiple entries were selected, don't + * touch the controls.) */ + char *val = strchr(p, '\t'); + if (val) { + int ind = 0; + val++; + while (ttymodes[ind]) { + if (strlen(ttymodes[ind]) == val-p-1 && + !strncmp(ttymodes[ind], p, val-p-1)) + break; + ind++; + } + dlg_listbox_select(td->modelist, dlg, ind); + dlg_radiobutton_set(td->valradio, dlg, + (*val == 'V')); + dlg_editbox_set(td->valbox, dlg, val+1); + } + } memmove(p, p+strlen(p)+1, len - (strlen(p)+1)); i++; continue; @@ -866,7 +921,7 @@ static void environ_handler(union control *ctrl, void *dlg, if (i < 0) { dlg_beep(dlg); } else { - char *p, *q; + char *p, *q, *str; dlg_listbox_del(ed->listbox, dlg, i); p = cfg->environmt; @@ -881,8 +936,20 @@ static void environ_handler(union control *ctrl, void *dlg, q = p; if (!*p) goto disaster; - while (*p) - p++; + /* Populate controls with the entry we're about to delete + * for ease of editing */ + str = p; + p = strchr(p, '\t'); + if (!p) + goto disaster; + *p = '\0'; + dlg_editbox_set(ed->varbox, dlg, str); + p++; + str = p; + dlg_editbox_set(ed->valbox, dlg, str); + p = strchr(p, '\0'); + if (!p) + goto disaster; p++; while (*p) { while (*p) @@ -976,26 +1043,33 @@ static void portfwd_handler(union control *ctrl, void *dlg, *p = '\0'; p = cfg->portfwd; while (*p) { + if (strcmp(p,str) == 0) { + dlg_error_msg(dlg, "Specified forwarding already exists"); + break; + } while (*p) p++; p++; } - if ((p - cfg->portfwd) + strlen(str) + 2 <= - sizeof(cfg->portfwd)) { - strcpy(p, str); - p[strlen(str) + 1] = '\0'; - dlg_listbox_add(pfd->listbox, dlg, str); - dlg_editbox_set(pfd->sourcebox, dlg, ""); - dlg_editbox_set(pfd->destbox, dlg, ""); - } else { - dlg_error_msg(dlg, "Too many forwardings"); + if (!*p) { + if ((p - cfg->portfwd) + strlen(str) + 2 <= + sizeof(cfg->portfwd)) { + strcpy(p, str); + p[strlen(str) + 1] = '\0'; + dlg_listbox_add(pfd->listbox, dlg, str); + dlg_editbox_set(pfd->sourcebox, dlg, ""); + dlg_editbox_set(pfd->destbox, dlg, ""); + } else { + dlg_error_msg(dlg, "Too many forwardings"); + } } } else if (ctrl == pfd->rembutton) { int i = dlg_listbox_index(pfd->listbox, dlg); if (i < 0) dlg_beep(dlg); else { - char *p, *q; + char *p, *q, *src, *dst; + char dir; dlg_listbox_del(pfd->listbox, dlg, i); p = cfg->portfwd; @@ -1010,8 +1084,44 @@ static void portfwd_handler(union control *ctrl, void *dlg, q = p; if (!*p) goto disaster2; - while (*p) + /* Populate the controls with the entry we're about to + * delete, for ease of editing. */ + { + static const char *const afs = "A46"; + char *afp = strchr(afs, *p); +#ifndef NO_IPV6 + int idx = afp ? afp-afs : 0; +#endif + if (afp) + p++; +#ifndef NO_IPV6 + dlg_radiobutton_set(pfd->addressfamily, dlg, idx); +#endif + } + { + static const char *const dirs = "LRD"; + dir = *p; + dlg_radiobutton_set(pfd->direction, dlg, + strchr(dirs, dir) - dirs); + } + p++; + if (dir != 'D') { + src = p; + p = strchr(p, '\t'); + if (!p) + goto disaster2; + *p = '\0'; p++; + dst = p; + } else { + src = p; + dst = ""; + } + p = strchr(p, '\0'); + if (!p) + goto disaster2; + dlg_editbox_set(pfd->sourcebox, dlg, src); + dlg_editbox_set(pfd->destbox, dlg, dst); p++; while (*p) { while (*p) @@ -1089,11 +1199,11 @@ void setup_config_box(struct controlbox *b, int midsession, hp->port = c; ctrl_columns(s, 1, 100); - if (!have_backend(PROT_SSH)) { + if (!backend_from_proto(PROT_SSH)) { ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3, HELPCTX(session_hostname), config_protocolbuttons_handler, P(hp), - "Raw", 'r', I(PROT_RAW), + "Raw", 'w', I(PROT_RAW), "Telnet", 't', I(PROT_TELNET), "Rlogin", 'i', I(PROT_RLOGIN), NULL); @@ -1101,7 +1211,7 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4, HELPCTX(session_hostname), config_protocolbuttons_handler, P(hp), - "Raw", 'r', I(PROT_RAW), + "Raw", 'w', I(PROT_RAW), "Telnet", 't', I(PROT_TELNET), "Rlogin", 'i', I(PROT_RLOGIN), "SSH", 's', I(PROT_SSH), @@ -1159,7 +1269,7 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_columns(s, 1, 100); s = ctrl_getset(b, "Session", "otheropts", NULL); - c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4, + c = ctrl_radiobuttons(s, "Close window on exit:", 'x', 4, HELPCTX(session_coe), dlg_stdradiobutton_handler, I(offsetof(Config, close_on_exit)), @@ -1180,7 +1290,7 @@ void setup_config_box(struct controlbox *b, int midsession, { char *sshlogname, *sshrawlogname; if ((midsession && protocol == PROT_SSH) || - (!midsession && have_backend(PROT_SSH))) { + (!midsession && backend_from_proto(PROT_SSH))) { sshlogname = "SSH packets"; sshrawlogname = "SSH packets and raw data"; } else { @@ -1216,7 +1326,7 @@ void setup_config_box(struct controlbox *b, int midsession, dlg_stdcheckbox_handler, I(offsetof(Config,logflush))); if ((midsession && protocol == PROT_SSH) || - (!midsession && have_backend(PROT_SSH))) { + (!midsession && backend_from_proto(PROT_SSH))) { s = ctrl_getset(b, "Session/Logging", "ssh", "Options specific to SSH packet logging"); ctrl_checkbox(s, "Omit known password fields", 'k', @@ -1242,6 +1352,9 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_checkbox(s, "Implicit CR in every LF", 'r', HELPCTX(terminal_lfhascr), dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr))); + ctrl_checkbox(s, "Implicit LF in every CR", 'f', + HELPCTX(terminal_crhaslf), + dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf))); ctrl_checkbox(s, "Use background colour to erase screen", 'e', HELPCTX(terminal_bce), dlg_stdcheckbox_handler, I(offsetof(Config,bce))); @@ -1399,13 +1512,13 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Window", "size", "Set the size of the window"); ctrl_columns(s, 2, 50, 50); - c = ctrl_editbox(s, "Rows", 'r', 100, - HELPCTX(window_size), - dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1)); - c->generic.column = 0; c = ctrl_editbox(s, "Columns", 'm', 100, HELPCTX(window_size), dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1)); + c->generic.column = 0; + c = ctrl_editbox(s, "Rows", 'r', 100, + HELPCTX(window_size), + dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1)); c->generic.column = 1; ctrl_columns(s, 1, 100); @@ -1497,8 +1610,8 @@ void setup_config_box(struct controlbox *b, int midsession, "Options controlling character set translation"); s = ctrl_getset(b, "Window/Translation", "trans", - "Character set translation on received data"); - ctrl_combobox(s, "Received data assumed to be in which character set:", + "Character set translation"); + ctrl_combobox(s, "Remote character set:", 'r', 100, HELPCTX(translation_codepage), codepage_handler, P(NULL), P(NULL)); @@ -1648,6 +1761,18 @@ void setup_config_box(struct controlbox *b, int midsession, "IPv6", '6', I(ADDRTYPE_IPV6), NULL); #endif + + { + 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", + "Logical name of remote host"); + ctrl_editbox(s, label, 'm', 100, + HELPCTX(connection_loghost), + dlg_stdeditbox_handler, I(offsetof(Config,loghost)), + I(sizeof(((Config *)0)->loghost))); + } } /* @@ -1663,6 +1788,22 @@ void setup_config_box(struct controlbox *b, int midsession, HELPCTX(connection_username), dlg_stdeditbox_handler, I(offsetof(Config,username)), I(sizeof(((Config *)0)->username))); + { + /* We assume the local username is sufficiently stable + * to include on the dialog box. */ + char *user = get_username(); + char *userlabel = dupprintf("Use system username (%s)", + user ? user : ""); + sfree(user); + ctrl_radiobuttons(s, "When username is not specified:", 'n', 4, + HELPCTX(connection_username_from_env), + dlg_stdradiobutton_handler, + I(offsetof(Config, username_from_env)), + "Prompt", I(FALSE), + userlabel, I(TRUE), + NULL); + sfree(userlabel); + } s = ctrl_getset(b, "Connection/Data", "term", "Terminal details"); @@ -1835,7 +1976,7 @@ void setup_config_box(struct controlbox *b, int midsession, * when we're not doing SSH. */ - if (have_backend(PROT_SSH) && (!midsession || protocol == PROT_SSH)) { + if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) { /* * The Connection/SSH panel. @@ -1963,19 +2104,44 @@ void setup_config_box(struct controlbox *b, int midsession, dlg_stdcheckbox_handler, I(offsetof(Config,try_ki_auth))); +#ifndef NO_GSSAPI + ctrl_checkbox(s, "Attempt GSSAPI auth (SSH-2)", + NO_SHORTCUT, HELPCTX(no_help), + dlg_stdcheckbox_handler, + I(offsetof(Config,try_gssapi_auth))); +#endif + s = ctrl_getset(b, "Connection/SSH/Auth", "params", "Authentication parameters"); ctrl_checkbox(s, "Allow agent forwarding", 'f', HELPCTX(ssh_auth_agentfwd), dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd))); - ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u', + ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT, HELPCTX(ssh_auth_changeuser), dlg_stdcheckbox_handler, I(offsetof(Config,change_username))); +#ifndef NO_GSSAPI + ctrl_checkbox(s, "Allow GSSAPI credential delegation in SSH-2", NO_SHORTCUT, + HELPCTX(no_help), + dlg_stdcheckbox_handler, + I(offsetof(Config,gssapifwd))); +#endif ctrl_filesel(s, "Private key file for authentication:", 'k', FILTER_KEY_FILES, FALSE, "Select private key file", HELPCTX(ssh_auth_privkey), dlg_stdfilesel_handler, I(offsetof(Config, keyfile))); + +#ifndef NO_GSSAPI + /* + * GSSAPI library selection. + */ + if (ngsslibs > 1) { + c = ctrl_draglist(s, "Preference order for GSSAPI libraries:", NO_SHORTCUT, + HELPCTX(no_help), + gsslist_handler, P(NULL)); + c->listbox.height = ngsslibs; + } +#endif } if (!midsession) { @@ -2157,6 +2323,9 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20, HELPCTX(ssh_bugs_rsa1), sshbug_handler, I(offsetof(Config,sshbug_rsa1))); + ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20, + HELPCTX(ssh_bugs_ignore2), + sshbug_handler, I(offsetof(Config,sshbug_ignore2))); ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20, HELPCTX(ssh_bugs_hmac2), sshbug_handler, I(offsetof(Config,sshbug_hmac2))); @@ -2172,6 +2341,9 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20, HELPCTX(ssh_bugs_rekey2), sshbug_handler, I(offsetof(Config,sshbug_rekey2))); + ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20, + HELPCTX(ssh_bugs_maxpkt2), + sshbug_handler, I(offsetof(Config,sshbug_maxpkt2))); } } }