From f80955488acdd3deccfc55dbff23124dd20318af Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 26 Sep 2024 10:50:47 +0100 Subject: [PATCH] Switch CONF_remote_cmd to being STR_AMBI. The immediate usefulness of this is in pterm.exe: when the user uses -e to specify a command to run in the pterm, we retrieve the command in Unicode, store it in CONF_remote_cmd as UTF-8, and then in conpty.c we can extract it in the same form and convert it back to Unicode to pass losslessly to CreateProcessW. So now non-ACP Unicode works in that part of the pterm command line. --- conf.h | 4 ++-- ssh/mainchan.c | 10 +++++++--- test/test_conf.c | 2 +- unix/plink.c | 4 ++-- windows/conpty.c | 25 +++++++++++++++---------- windows/plink.c | 4 ++-- windows/pterm.c | 4 ++-- 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/conf.h b/conf.h index ce336b99..25e3333d 100644 --- a/conf.h +++ b/conf.h @@ -154,7 +154,7 @@ CONF_OPTION(proxy_log_to_term, /* SSH options */ CONF_OPTION(remote_cmd, - VALUE_TYPE(STR), + VALUE_TYPE(STR_AMBI), DEFAULT_STR(""), SAVE_KEYWORD("RemoteCommand"), ) @@ -165,7 +165,7 @@ CONF_OPTION(remote_cmd2, * methods of running an SFTP server at the remote end); never set * by user configuration, or loaded or saved. */ - VALUE_TYPE(STR), + VALUE_TYPE(STR_AMBI), DEFAULT_STR(""), NOT_SAVED, ) diff --git a/ssh/mainchan.c b/ssh/mainchan.c index 52492ff6..b671ba1a 100644 --- a/ssh/mainchan.c +++ b/ssh/mainchan.c @@ -182,7 +182,9 @@ static void mainchan_open_confirmation(Channel *chan) if (mc->n_req_env) ppl_logevent("Sent %d environment variables", mc->n_req_env); - cmd = conf_get_str(mc->conf, CONF_remote_cmd); + /* Ignore encoding of CONF_remote_cmd so as not to disturb + * legacy handling of non-UTF-8 commands */ + cmd = conf_get_str_ambi(mc->conf, CONF_remote_cmd, NULL); if (conf_get_bool(mc->conf, CONF_ssh_subsys)) { retry_cmd_now = !sshfwd_start_subsystem(mc->sc, true, cmd); } else if (*cmd) { @@ -205,7 +207,9 @@ static void mainchan_open_confirmation(Channel *chan) static void mainchan_try_fallback_command(mainchan *mc) { - const char *cmd = conf_get_str(mc->conf, CONF_remote_cmd2); + /* Ignore encoding of CONF_remote_cmd2 so as not to disturb legacy + * handling of non-UTF-8 commands */ + const char *cmd = conf_get_str_ambi(mc->conf, CONF_remote_cmd2, NULL); if (conf_get_bool(mc->conf, CONF_ssh_subsys2)) { sshfwd_start_subsystem(mc->sc, true, cmd); } else { @@ -288,7 +292,7 @@ static void mainchan_request_response(Channel *chan, bool success) if (success) { ppl_logevent("Started a shell/command"); mainchan_ready(mc); - } else if (*conf_get_str(mc->conf, CONF_remote_cmd2)) { + } else if (*conf_get_str_ambi(mc->conf, CONF_remote_cmd2, NULL)) { ppl_logevent("Primary command failed; attempting fallback"); mainchan_try_fallback_command(mc); } else { diff --git a/test/test_conf.c b/test/test_conf.c index d71ea634..33a25a48 100644 --- a/test/test_conf.c +++ b/test/test_conf.c @@ -696,7 +696,7 @@ void test_simple(void) test_str_simple(CONF_proxy_telnet_command, "ProxyTelnetCommand", "connect %host %port\\n"); test_int_translated(CONF_proxy_log_to_term, "ProxyLogToTerm", FORCE_OFF, FORCE_ON, 0, FORCE_OFF, 1, AUTO, 2, -1); - test_str_simple(CONF_remote_cmd, "RemoteCommand", ""); + test_str_ambi_simple(CONF_remote_cmd, "RemoteCommand", "", false); test_bool_simple(CONF_nopty, "NoPTY", false); test_bool_simple(CONF_compression, "Compression", false); test_bool_simple(CONF_ssh_prefer_known_hostkeys, "PreferKnownHostKeys", true); diff --git a/unix/plink.c b/unix/plink.c index 36bf29d1..b4a9749f 100644 --- a/unix/plink.c +++ b/unix/plink.c @@ -394,8 +394,8 @@ static SeatPromptResult plink_get_userpass_input(Seat *seat, prompts_t *p) static bool plink_seat_interactive(Seat *seat) { - return (!*conf_get_str(conf, CONF_remote_cmd) && - !*conf_get_str(conf, CONF_remote_cmd2) && + return (!*conf_get_str_ambi(conf, CONF_remote_cmd, NULL) && + !*conf_get_str_ambi(conf, CONF_remote_cmd2, NULL) && !*conf_get_str(conf, CONF_ssh_nc_host)); } diff --git a/windows/conpty.c b/windows/conpty.c index c23c81e1..27e6f552 100644 --- a/windows/conpty.c +++ b/windows/conpty.c @@ -176,7 +176,7 @@ static char *conpty_init(const BackendVtable *vt, Seat *seat, HPCON pcon; bool pcon_needs_cleanup = false; - STARTUPINFOEX si; + STARTUPINFOEXW si; memset(&si, 0, sizeof(si)); if (!init_conpty_api()) { @@ -238,16 +238,21 @@ static char *conpty_init(const BackendVtable *vt, Seat *seat, PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); - char *command; - const char *conf_cmd = conf_get_str(conf, CONF_remote_cmd); - if (*conf_cmd) { - command = dupstr(conf_cmd); - } else { - command = dupcat(get_system_dir(), "\\cmd.exe"); + wchar_t *command; + { + bool utf8; + const char *conf_cmd = conf_get_str_ambi(conf, CONF_remote_cmd, &utf8); + if (*conf_cmd) { + command = dup_mb_to_wc(utf8 ? CP_UTF8 : CP_ACP, conf_cmd); + } else { + char *cmd = dupcat(get_system_dir(), "\\cmd.exe"); + command = dup_mb_to_wc(CP_ACP, cmd); + sfree(cmd); + } } - bool created_ok = CreateProcess(NULL, command, NULL, NULL, - false, EXTENDED_STARTUPINFO_PRESENT, - NULL, NULL, &si.StartupInfo, &pi); + bool created_ok = CreateProcessW(NULL, command, NULL, NULL, + false, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, &si.StartupInfo, &pi); sfree(command); if (!created_ok) { err = dupprintf("CreateProcess: %s", diff --git a/windows/plink.c b/windows/plink.c index 46773815..8b871912 100644 --- a/windows/plink.c +++ b/windows/plink.c @@ -82,8 +82,8 @@ static SeatPromptResult plink_get_userpass_input(Seat *seat, prompts_t *p) static bool plink_seat_interactive(Seat *seat) { - return (!*conf_get_str(conf, CONF_remote_cmd) && - !*conf_get_str(conf, CONF_remote_cmd2) && + return (!*conf_get_str_ambi(conf, CONF_remote_cmd, NULL) && + !*conf_get_str_ambi(conf, CONF_remote_cmd2, NULL) && !*conf_get_str(conf, CONF_ssh_nc_host)); } diff --git a/windows/pterm.c b/windows/pterm.c index fd921f09..2b05fe08 100644 --- a/windows/pterm.c +++ b/windows/pterm.c @@ -32,8 +32,8 @@ void gui_term_process_cmdline(Conf *conf, char *cmdline) if (nextarg) { /* The command to execute is taken to be the unparsed * version of the whole remainder of the command line. */ - char *cmd = cmdline_arg_remainder_acp(nextarg); - conf_set_str(conf, CONF_remote_cmd, cmd); + char *cmd = cmdline_arg_remainder_utf8(nextarg); + conf_set_utf8(conf, CONF_remote_cmd, cmd); sfree(cmd); return; } else {