Index: cmdline.c =================================================================== --- cmdline.c (revision 29733) +++ cmdline.c (working copy) @@ -186,11 +186,11 @@ } int cmdline_process_param(const char *p, char *value, - int need_save, Conf *conf) + int need_save, Conf *conf, bool ignoreFurtherParameters) { int ret = 0; - if (p[0] != '-') { + if (p[0] != '-' || ignoreFurtherParameters) { if (need_save < 0) return 0; @@ -404,7 +404,7 @@ * deferred until it's a good moment to run it. */ char *dup = dupstr(p); /* 'value' is not a const char * */ - int retd = cmdline_process_param("-P", dup, 1, conf); + int retd = cmdline_process_param("-P", dup, 1, conf, false); sfree(dup); assert(retd == 2); seen_port_argument = true; @@ -418,6 +418,9 @@ } } + if (ignoreFurtherParameters) + return ret; + if (!strcmp(p, "-load")) { RETURN(2); /* This parameter must be processed immediately rather than being @@ -581,12 +584,24 @@ conf_set_bool(conf, CONF_nopty, true); /* command => no terminal */ strbuf_free(command); } - if (!strcmp(p, "-P")) { + if (!strcmp(p, "-P") || !strcmp(p, "-p")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(1); /* lower priority than -ssh, -telnet, etc */ conf_set_int(conf, CONF_port, atoi(value)); } + if (!strcmp(p, "-o")) { + RETURN(2); + UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); + SAVEABLE(0); + if (stricmp(value, "SendEnv=GIT_PROTOCOL")) { + cmdline_error("Unrecognised suboption \"-o %s\"", value); + return -1; + } + const char *env = getenv("GIT_PROTOCOL"); + if (env) + conf_set_str_str(conf, CONF_environmt, "GIT_PROTOCOL", env); + } if (!strcmp(p, "-pw")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); @@ -925,7 +940,7 @@ for (size_t pri = 0; pri < NPRIORITIES; pri++) { for (size_t i = 0; i < saves[pri].nsaved; i++) { cmdline_process_param(saves[pri].params[i].p, - saves[pri].params[i].value, 0, conf); + saves[pri].params[i].value, 0, conf, false); sfree(saves[pri].params[i].p); sfree(saves[pri].params[i].value); } Index: console.c =================================================================== --- console.c (revision 29733) +++ console.c (working copy) @@ -9,17 +9,17 @@ #include "misc.h" #include "console.h" -const char console_abandoned_msg[] = "Connection abandoned.\n"; +//const char console_abandoned_msg[] = "Connection abandoned.\n"; const SeatDialogPromptDescriptions *console_prompt_descriptions(Seat *seat) { static const SeatDialogPromptDescriptions descs = { - .hk_accept_action = "enter \"y\"", - .hk_connect_once_action = "enter \"n\"", - .hk_cancel_action = "press Return", - .hk_cancel_action_Participle = "Pressing Return", - .weak_accept_action = "enter \"y\"", - .weak_cancel_action = "enter \"n\"", + .hk_accept_action = "hit Yes", + .hk_connect_once_action = "hit No", + .hk_cancel_action = "hit Cancel", + .hk_cancel_action_Participle = "Hitting Cancel", + .weak_accept_action = "hit Yes", + .weak_cancel_action = "hit No", }; return &descs; } @@ -30,28 +30,16 @@ * Error message and/or fatal exit functions, all based on * console_print_error_msg which the platform front end provides. */ -void console_print_error_msg_fmt_v( - const char *prefix, const char *fmt, va_list ap) -{ - char *msg = dupvprintf(fmt, ap); - console_print_error_msg(prefix, msg); - sfree(msg); -} - -void console_print_error_msg_fmt(const char *prefix, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - console_print_error_msg_fmt_v(prefix, fmt, ap); - va_end(ap); -} - void modalfatalbox(const char *fmt, ...) { va_list ap; + char *stuff, morestuff[100]; va_start(ap, fmt); - console_print_error_msg_fmt_v("FATAL ERROR", fmt, ap); + stuff = dupvprintf(fmt, ap); va_end(ap); + sprintf(morestuff, "%.70s Fatal Error", appname); + MessageBox(GetParentHwnd(), stuff, morestuff, MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); + sfree(stuff); cleanup_exit(1); } @@ -58,14 +46,20 @@ void nonfatal(const char *fmt, ...) { va_list ap; + char *stuff, morestuff[100]; va_start(ap, fmt); - console_print_error_msg_fmt_v("ERROR", fmt, ap); + stuff = dupvprintf(fmt, ap); va_end(ap); + sprintf(morestuff, "%.70s Error", appname); + MessageBox(GetParentHwnd(), stuff, morestuff, MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); + sfree(stuff); } void console_connection_fatal(Seat *seat, const char *msg) { - console_print_error_msg("FATAL ERROR", msg); + char morestuff[100]; + sprintf(morestuff, "%.70s Fatal Error", appname); + MessageBox(GetParentHwnd(), msg, morestuff, MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); cleanup_exit(1); } Index: putty.h =================================================================== --- putty.h (revision 29733) +++ putty.h (working copy) @@ -2588,7 +2588,7 @@ struct cmdline_get_passwd_input_state { bool tried #define CMDLINE_GET_PASSWD_INPUT_STATE_INIT { .tried = false } extern const cmdline_get_passwd_input_state cmdline_get_passwd_input_state_new; -int cmdline_process_param(const char *, char *, int, Conf *); +int cmdline_process_param(const char *, char *, int, Conf *, bool); void cmdline_run_saved(Conf *); void cmdline_cleanup(void); SeatPromptResult cmdline_get_passwd_input( Index: ssh/common.c =================================================================== --- ssh/common.c (revision 29733) +++ ssh/common.c (working copy) @@ -984,6 +984,8 @@ text, SDT_PARA, "The new %s key fingerprint is:", keytype); seat_dialog_text_append( text, SDT_DISPLAY, "%s", fingerprints[fptype_default]); + seat_dialog_text_append( + text, SDT_DISPLAY, "%s", fingerprints[SSH_FPTYPE_MD5]); helpctx = HELPCTX(errors_cert_mismatch); } else if (storage_status == 1) { seat_dialog_text_append( @@ -997,6 +999,8 @@ text, SDT_PARA, "The server's %s key fingerprint is:", keytype); seat_dialog_text_append( text, SDT_DISPLAY, "%s", fingerprints[fptype_default]); + seat_dialog_text_append( + text, SDT_DISPLAY, "%s", fingerprints[SSH_FPTYPE_MD5]); helpctx = HELPCTX(errors_hostkey_absent); } else { seat_dialog_text_append( @@ -1014,6 +1018,8 @@ text, SDT_PARA, "The new %s key fingerprint is:", keytype); seat_dialog_text_append( text, SDT_DISPLAY, "%s", fingerprints[fptype_default]); + seat_dialog_text_append( + text, SDT_DISPLAY, "%s", fingerprints[SSH_FPTYPE_MD5]); helpctx = HELPCTX(errors_hostkey_changed); } Index: version.h =================================================================== --- version.h (revision 29733) +++ version.h (working copy) @@ -1,5 +1,5 @@ /* Generated by automated build script */ #define RELEASE 0.81 #define TEXTVER "Release 0.81" -#define SSHVER "-Release-0.81" +#define SSHVER "TortoisePlink-Release-0.81" #define BINARY_VERSION 0,81,0,0 Index: windows/console.c =================================================================== --- windows/console.c (revision 29733) +++ windows/console.c (working copy) @@ -11,6 +11,8 @@ #include "ssh.h" #include "console.h" +#include "LoginDialog.h" + void cleanup_exit(int code) { /* @@ -23,15 +25,6 @@ exit(code); } -void console_print_error_msg(const char *prefix, const char *msg) -{ - fputs(prefix, stderr); - fputs(": ", stderr); - fputs(msg, stderr); - fputc('\n', stderr); - fflush(stderr); -} - /* * Helper function to print the message from a SeatDialogText. Returns * the final prompt to print on the input line, or NULL if a @@ -38,43 +31,50 @@ * batch-mode abort is needed. In the latter case it will have printed * the abort text already. */ -static const char *console_print_seatdialogtext(SeatDialogText *text) +static strbuf *console_print_seatdialogtext(SeatDialogText *text, const char **title) { - const char *prompt = NULL; - stdio_sink errsink[1]; - stdio_sink_init(errsink, stderr); + strbuf* buf = strbuf_new(); + assert(title); + *title = NULL; + for (SeatDialogTextItem *item = text->items, *end = item+text->nitems; item < end; item++) { switch (item->type) { + case SDT_TITLE: + *title = item->text; + break; case SDT_PARA: - wordwrap(BinarySink_UPCAST(errsink), - ptrlen_from_asciz(item->text), 60); - fputc('\n', stderr); + put_dataz(buf, item->text); + put_dataz(buf, "\n"); break; case SDT_DISPLAY: - fprintf(stderr, " %s\n", item->text); + put_dataz(buf, " "); + put_dataz(buf, item->text); + put_dataz(buf, "\n"); break; case SDT_SCARY_HEADING: /* Can't change font size or weight in this context */ - fprintf(stderr, "%s\n", item->text); + put_dataz(buf, item->text); + put_dataz(buf, "\n"); + put_dataz(buf, "\n"); break; case SDT_BATCH_ABORT: if (console_batch_mode) { - fprintf(stderr, "%s\n", item->text); - fflush(stderr); + strbuf_free(buf); return NULL; } break; case SDT_PROMPT: - prompt = item->text; + put_dataz(buf, "\n"); + put_dataz(buf, item->text); break; default: break; } } - assert(prompt); /* something in the SeatDialogText should have set this */ - return prompt; + assert(*title); + return buf; } SeatPromptResult console_confirm_ssh_host_key( @@ -82,61 +82,26 @@ char *keystr, SeatDialogText *text, HelpCtx helpctx, void (*callback)(void *ctx, SeatPromptResult result), void *ctx) { - HANDLE hin; - DWORD savemode, i; + int mbret; + const char* title = NULL; - const char *prompt = console_print_seatdialogtext(text); - if (!prompt) + strbuf *buf = console_print_seatdialogtext(text, &title); + if (!buf) return SPR_SW_ABORT("Cannot confirm a host key in batch mode"); - char line[32]; - - while (true) { - fprintf(stderr, - "%s (y/n, Return cancels connection, i for more info) ", - prompt); - fflush(stderr); - - line[0] = '\0'; /* fail safe if ReadFile returns no data */ - - hin = GetStdHandle(STD_INPUT_HANDLE); - GetConsoleMode(hin, &savemode); - SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT | - ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)); - ReadFile(hin, line, sizeof(line) - 1, &i, NULL); - SetConsoleMode(hin, savemode); - - if (line[0] == 'i' || line[0] == 'I') { - for (SeatDialogTextItem *item = text->items, - *end = item+text->nitems; item < end; item++) { - switch (item->type) { - case SDT_MORE_INFO_KEY: - fprintf(stderr, "%s", item->text); - break; - case SDT_MORE_INFO_VALUE_SHORT: - fprintf(stderr, ": %s\n", item->text); - break; - case SDT_MORE_INFO_VALUE_BLOB: - fprintf(stderr, ":\n%s\n", item->text); - break; - default: - break; - } - } - } else { - break; - } + mbret = MessageBox(GetParentHwnd(), buf->s, title, MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3); + strbuf_free(buf); + if (mbret == IDYES) + { + store_host_key(host, port, keytype, keystr); + return SPR_OK; } - - /* In case of misplaced reflexes from another program, also recognise 'q' - * as 'abandon connection rather than trust this key' */ - if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n' && - line[0] != 'q' && line[0] != 'Q') { - if (line[0] == 'y' || line[0] == 'Y') - store_host_key(host, port, keytype, keystr); + else if (mbret == IDNO) + { return SPR_OK; - } else { - fputs(console_abandoned_msg, stderr); + } + else + { return SPR_USER_ABORT; } } @@ -145,30 +110,23 @@ Seat *seat, SeatDialogText *text, void (*callback)(void *ctx, SeatPromptResult result), void *ctx) { - HANDLE hin; - DWORD savemode, i; + int mbret; + char *title = NULL; + static const char mbtitle[] = "%s Security Alert"; - const char *prompt = console_print_seatdialogtext(text); - if (!prompt) + strbuf* buf = console_print_seatdialogtext(text, &title); + if (!buf) return SPR_SW_ABORT("Cannot confirm a weak crypto primitive " "in batch mode"); - char line[32]; + title = dupprintf(mbtitle, appname); - fprintf(stderr, "%s (y/n) ", prompt); - fflush(stderr); - - hin = GetStdHandle(STD_INPUT_HANDLE); - GetConsoleMode(hin, &savemode); - SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT | - ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)); - ReadFile(hin, line, sizeof(line) - 1, &i, NULL); - SetConsoleMode(hin, savemode); - - if (line[0] == 'y' || line[0] == 'Y') { + mbret = MessageBox(GetParentHwnd(), buf->s, title, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2); + strbuf_free(buf); + sfree(title); + if (mbret == IDYES) { return SPR_OK; } else { - fputs(console_abandoned_msg, stderr); return SPR_USER_ABORT; } } @@ -177,30 +135,24 @@ Seat *seat, SeatDialogText *text, void (*callback)(void *ctx, SeatPromptResult result), void *ctx) { - HANDLE hin; - DWORD savemode, i; + int mbret; + char *title = NULL; + static const char mbtitle[] = "%s Security Alert"; - const char *prompt = console_print_seatdialogtext(text); - if (!prompt) + strbuf* buf = console_print_seatdialogtext(text, &title); + if (!buf) return SPR_SW_ABORT("Cannot confirm a weak cached host key " "in batch mode"); - char line[32]; + title = dupprintf(mbtitle, appname); - fprintf(stderr, "%s (y/n) ", prompt); - fflush(stderr); + mbret = MessageBox(GetParentHwnd(), buf->s, title, MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3); + strbuf_to_str(buf); + sfree(title); - hin = GetStdHandle(STD_INPUT_HANDLE); - GetConsoleMode(hin, &savemode); - SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT | - ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)); - ReadFile(hin, line, sizeof(line) - 1, &i, NULL); - SetConsoleMode(hin, savemode); - - if (line[0] == 'y' || line[0] == 'Y') { + if (mbret == IDYES) { return SPR_OK; } else { - fputs(console_abandoned_msg, stderr); return SPR_USER_ABORT; } } @@ -266,34 +218,28 @@ "You can overwrite it with a new session log,\n" "append your session log to the end of it,\n" "or disable session logging for this session.\n" - "Enter \"y\" to wipe the file, \"n\" to append to it,\n" - "or just press Return to disable logging.\n" - "Wipe the log file? (y/n, Return cancels logging) "; + "Hit Yes to wipe the file, hit No to append to it,\n" + "or just press Cancel to disable logging.\n" + "Wipe the log file?"; static const char msgtemplate_batch[] = "The session log file \"%.*s\" already exists.\n" "Logging will not be enabled.\n"; - char line[32]; + int mbret; + char *message, *title; + static const char mbtitle[] = "%s Session log"; - if (console_batch_mode) { - fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename->path); - fflush(stderr); - return 0; - } - fprintf(stderr, msgtemplate, FILENAME_MAX, filename->path); - fflush(stderr); + message = dupprintf(msgtemplate, FILENAME_MAX, filename->path); + title = dupprintf(mbtitle, appname); - hin = GetStdHandle(STD_INPUT_HANDLE); - GetConsoleMode(hin, &savemode); - SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT | - ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)); - ReadFile(hin, line, sizeof(line) - 1, &i, NULL); - SetConsoleMode(hin, savemode); + mbret = MessageBox(GetParentHwnd(), message, title, MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3); + sfree(message); + sfree(title); - if (line[0] == 'y' || line[0] == 'Y') + if (mbret == IDYES) return 2; - else if (line[0] == 'n' || line[0] == 'N') + else if (mbret == IDNO) return 1; else return 0; @@ -385,119 +331,18 @@ prompt_set_result(p->prompts[i], ""); } - /* - * The prompts_t might contain a message to be displayed but no - * actual prompt. More usually, though, it will contain - * questions that the user needs to answer, in which case we - * need to ensure that we're able to get the answers. - */ - if (p->n_prompts) { - if (console_batch_mode) - return SPR_SW_ABORT("Cannot answer interactive prompts " - "in batch mode"); - hin = GetStdHandle(STD_INPUT_HANDLE); - if (hin == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Cannot get standard input handle\n"); - cleanup_exit(1); - } - } + if (console_batch_mode) + return SPR_USER_ABORT; - /* - * And if we have anything to print, we need standard output. - */ - if ((p->name_reqd && p->name) || p->instruction || p->n_prompts) { - hout = GetStdHandle(STD_OUTPUT_HANDLE); - if (hout == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Cannot get standard output handle\n"); - cleanup_exit(1); - } - } - - /* - * Preamble. - */ - /* We only print the `name' caption if we have to... */ - if (p->name_reqd && p->name) { - ptrlen plname = ptrlen_from_asciz(p->name); - console_write(hout, plname); - if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL)) - console_write(hout, PTRLEN_LITERAL("\n")); - } - /* ...but we always print any `instruction'. */ - if (p->instruction) { - ptrlen plinst = ptrlen_from_asciz(p->instruction); - console_write(hout, plinst); - if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL)) - console_write(hout, PTRLEN_LITERAL("\n")); - } - for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) { - DWORD savemode, newmode; prompt_t *pr = p->prompts[curr_prompt]; - GetConsoleMode(hin, &savemode); - newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT; - if (!pr->echo) - newmode &= ~ENABLE_ECHO_INPUT; - else - newmode |= ENABLE_ECHO_INPUT; - SetConsoleMode(hin, newmode); - - console_write(hout, ptrlen_from_asciz(pr->prompt)); - - bool failed = false; - SeatPromptResult spr; - while (1) { - /* - * Amount of data to try to read from the console in one - * go. This isn't completely arbitrary: a user reported - * that trying to read more than 31366 bytes at a time - * would fail with ERROR_NOT_ENOUGH_MEMORY on Windows 7, - * and Ruby's Win32 support module has evidence of a - * similar workaround: - * - * https://github.com/ruby/ruby/blob/0aa5195262d4193d3accf3e6b9bad236238b816b/win32/win32.c#L6842 - * - * To keep things simple, I stick with a nice round power - * of 2 rather than trying to go to the very limit of that - * bug. (We're typically reading user passphrases and the - * like here, so even this much is overkill really.) - */ - DWORD toread = 16384; - - size_t prev_result_len = pr->result->len; - void *ptr = strbuf_append(pr->result, toread); - - DWORD ret = 0; - if (!ReadFile(hin, ptr, toread, &ret, NULL)) { - /* An OS error when reading from the console is treated as an - * unexpected error and reported to the user. */ - failed = true; - spr = make_spr_sw_abort_winerror( - "Error reading from console", GetLastError()); - break; - } else if (ret == 0) { - /* Regard EOF on the terminal as a deliberate user-abort */ - failed = true; - spr = SPR_USER_ABORT; - break; - } - - strbuf_shrink_to(pr->result, prev_result_len + ret); - if (strbuf_chomp(pr->result, '\n')) { - strbuf_chomp(pr->result, '\r'); - break; - } - } - - SetConsoleMode(hin, savemode); - - if (!pr->echo) - console_write(hout, PTRLEN_LITERAL("\r\n")); - - if (failed) - return spr; + char result[MAX_LENGTH_PASSWORD] = { 0 }; + if (!DoLoginDialog(result, sizeof(result), pr->prompt)) + return SPR_USER_ABORT; + prompt_set_result(pr, result); + SecureZeroMemory(&result, sizeof(result)); } return SPR_OK; Index: windows/plink.c =================================================================== --- windows/plink.c (revision 29733) +++ windows/plink.c (working copy) @@ -1,4 +1,4 @@ -/* +/* * PLink - a Windows command-line (stdin/stdout) variant of PuTTY. */ @@ -13,12 +13,22 @@ #include "tree234.h" #include "security-api.h" +extern HWND GetParentHwnd(); + +#include +#pragma comment(lib, "comctl32.lib") +#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + void cmdline_error(const char *fmt, ...) { va_list ap; + char *stuff, morestuff[100]; va_start(ap, fmt); - console_print_error_msg_fmt_v("plink", fmt, ap); + stuff = dupvprintf(fmt, ap); va_end(ap); + sprintf(morestuff, "%.70s Command Line Error", appname); + MessageBox(GetParentHwnd(), stuff, morestuff, MB_ICONERROR | MB_OK); + sfree(stuff); exit(1); } @@ -126,76 +136,81 @@ */ static void usage(void) { - printf("Plink: command-line connection utility\n"); - printf("%s\n", ver); - printf("Usage: plink [options] [user@]host [command]\n"); - printf(" (\"host\" can also be a PuTTY saved session name)\n"); - printf("Options:\n"); - printf(" -V print version information and exit\n"); - printf(" -pgpfp print PGP key fingerprints and exit\n"); - printf(" -v show verbose messages\n"); - printf(" -load sessname Load settings from saved session\n"); - printf(" -ssh -telnet -rlogin -raw -serial\n"); - printf(" force use of a particular protocol\n"); - printf(" -ssh-connection\n"); - printf(" force use of the bare ssh-connection protocol\n"); - printf(" -P port connect to specified port\n"); - printf(" -l user connect with specified username\n"); - printf(" -batch disable all interactive prompts\n"); - printf(" -proxycmd command\n"); - printf(" use 'command' as local proxy\n"); - printf(" -sercfg configuration-string (e.g. 19200,8,n,1,X)\n"); - printf(" Specify the serial configuration (serial only)\n"); - printf("The following options only apply to SSH connections:\n"); - printf(" -pwfile file login with password read from specified file\n"); - printf(" -D [listen-IP:]listen-port\n"); - printf(" Dynamic SOCKS-based port forwarding\n"); - printf(" -L [listen-IP:]listen-port:host:port\n"); - printf(" Forward local port to remote address\n"); - printf(" -R [listen-IP:]listen-port:host:port\n"); - printf(" Forward remote port to local address\n"); - printf(" -X -x enable / disable X11 forwarding\n"); - printf(" -A -a enable / disable agent forwarding\n"); - printf(" -t -T enable / disable pty allocation\n"); - printf(" -1 -2 force use of particular SSH protocol version\n"); - printf(" -4 -6 force use of IPv4 or IPv6\n"); - printf(" -C enable compression\n"); - printf(" -i key private key file for user authentication\n"); - printf(" -noagent disable use of Pageant\n"); - printf(" -agent enable use of Pageant\n"); - printf(" -no-trivial-auth\n"); - printf(" disconnect if SSH authentication succeeds trivially\n"); - printf(" -noshare disable use of connection sharing\n"); - printf(" -share enable use of connection sharing\n"); - printf(" -hostkey keyid\n"); - printf(" manually specify a host key (may be repeated)\n"); - printf(" -sanitise-stderr, -sanitise-stdout, " - "-no-sanitise-stderr, -no-sanitise-stdout\n"); - printf(" do/don't strip control chars from standard " - "output/error\n"); - printf(" -no-antispoof omit anti-spoofing prompt after " - "authentication\n"); - printf(" -m file read remote command(s) from file\n"); - printf(" -s remote command is an SSH subsystem (SSH-2 only)\n"); - printf(" -N don't start a shell/command (SSH-2 only)\n"); - printf(" -nc host:port\n"); - printf(" open tunnel in place of session (SSH-2 only)\n"); - printf(" -sshlog file\n"); - printf(" -sshrawlog file\n"); - printf(" log protocol details to a file\n"); - printf(" -logoverwrite\n"); - printf(" -logappend\n"); - printf(" control what happens when a log file already exists\n"); - printf(" -shareexists\n"); - printf(" test whether a connection-sharing upstream exists\n"); + char buf[10000]; + int j = 0; + j += sprintf(buf + j, "TortoisePlink: command-line connection utility (based on PuTTY Plink)\n"); + j += sprintf(buf + j, "%s\n", ver); + j += sprintf(buf + j, "Usage: plink [options] [user@]host [command]\n"); + j += sprintf(buf + j, " (\"host\" can also be a PuTTY saved session name)\n"); + j += sprintf(buf + j, "Options:\n"); + j += sprintf(buf + j, " -V print version information and exit\n"); + j += sprintf(buf + j, " -pgpfp print PGP key fingerprints and exit\n"); + j += sprintf(buf + j, " -v show verbose messages\n"); + j += sprintf(buf + j, " -load sessname Load settings from saved session\n"); + j += sprintf(buf + j, " -ssh -telnet -rlogin -raw -serial\n"); + j += sprintf(buf + j, " force use of a particular protocol\n"); + j += sprintf(buf + j, " -ssh-connection\n"); + j += sprintf(buf + j, " force use of the bare ssh-connection protocol\n"); + j += sprintf(buf + j, " -P port connect to specified port\n"); + j += sprintf(buf + j, " -l user connect with specified username\n"); + j += sprintf(buf + j, " -batch disable all interactive prompts\n"); + j += sprintf(buf + j, " -proxycmd command\n"); + j += sprintf(buf + j, " use 'command' as local proxy\n"); + j += sprintf(buf + j, " -sercfg configuration-string (e.g. 19200,8,n,1,X)\n"); + j += sprintf(buf + j, " Specify the serial configuration (serial only)\n"); + j += sprintf(buf + j, "The following options only apply to SSH connections:\n"); + j += sprintf(buf + j, " -pwfile file login with password read from specified file\n"); + j += sprintf(buf + j, " -D [listen-IP:]listen-port\n"); + j += sprintf(buf + j, " Dynamic SOCKS-based port forwarding\n"); + j += sprintf(buf + j, " -L [listen-IP:]listen-port:host:port\n"); + j += sprintf(buf + j, " Forward local port to remote address\n"); + j += sprintf(buf + j, " -R [listen-IP:]listen-port:host:port\n"); + j += sprintf(buf + j, " Forward remote port to local address\n"); + j += sprintf(buf + j, " -X -x enable / disable X11 forwarding\n"); + j += sprintf(buf + j, " -A -a enable / disable agent forwarding\n"); + j += sprintf(buf + j, " -t -T enable / disable pty allocation\n"); + j += sprintf(buf + j, " -1 -2 force use of particular SSH protocol version\n"); + j += sprintf(buf + j, " -4 -6 force use of IPv4 or IPv6\n"); + j += sprintf(buf + j, " -C enable compression\n"); + j += sprintf(buf + j, " -i key private key file for user authentication\n"); + j += sprintf(buf + j, " -noagent disable use of Pageant\n"); + j += sprintf(buf + j, " -agent enable use of Pageant\n"); + j += sprintf(buf + j, " -no-trivial-auth\n"); + j += sprintf(buf + j, " disconnect if SSH authentication succeeds trivially\n"); + j += sprintf(buf + j, " -noshare disable use of connection sharing\n"); + j += sprintf(buf + j, " -share enable use of connection sharing\n"); + j += sprintf(buf + j, " -hostkey keyid\n"); + j += sprintf(buf + j, " manually specify a host key (may be repeated)\n"); + j += sprintf(buf + j, " -sanitise-stderr, -sanitise-stdout, "); + j += sprintf(buf + j, "-no-sanitise-stderr, -no-sanitise-stdout\n"); + j += sprintf(buf + j, " do/don't strip control chars from standard "); + j += sprintf(buf + j, "output/error\n"); + j += sprintf(buf + j, " -no-antispoof omit anti-spoofing prompt after "); + j += sprintf(buf + j, "authentication\n"); + j += sprintf(buf + j, " -m file read remote command(s) from file\n"); + j += sprintf(buf + j, " -s remote command is an SSH subsystem (SSH-2 only)\n"); + j += sprintf(buf + j, " -N don't start a shell/command (SSH-2 only)\n"); + j += sprintf(buf + j, " -nc host:port\n"); + j += sprintf(buf + j, " open tunnel in place of session (SSH-2 only)\n"); + j += sprintf(buf + j, " -sshlog file\n"); + j += sprintf(buf + j, " -sshrawlog file\n"); + j += sprintf(buf + j, " log protocol details to a file\n"); + j += sprintf(buf + j, " -logoverwrite\n"); + j += sprintf(buf + j, " -logappend\n"); + j += sprintf(buf + j, " control what happens when a log file already exists\n"); + j += sprintf(buf + j, " -shareexists\n"); + j += sprintf(buf + j, " test whether a connection-sharing upstream exists\n"); + MessageBox(NULL, buf, "TortoisePlink", MB_ICONINFORMATION); exit(1); } static void version(void) { - char *buildinfo_text = buildinfo("\n"); - printf("plink: %s\n%s\n", ver, buildinfo_text); + char buf[1000]; + char* buildinfo_text = buildinfo("\n"); + sprintf(buf, "TortoisePlink: %s\n%s\n", ver, buildinfo_text); sfree(buildinfo_text); + MessageBox(NULL, buf, "TortoisePlink", MB_ICONINFORMATION); exit(0); } @@ -297,6 +312,7 @@ dll_hijacking_protection(); + InitCommonControls(); /* * Initialise port and protocol to sensible defaults. (These * will be overridden by more or less anything.) @@ -309,65 +325,57 @@ */ conf = conf_new(); do_defaults(NULL, conf); - settings_set_default_protocol(conf_get_int(conf, CONF_protocol)); - settings_set_default_port(conf_get_int(conf, CONF_port)); + settings_set_default_protocol(PROT_SSH); + settings_set_default_port(22); errors = false; - { - /* - * Override the default protocol if PLINK_PROTOCOL is set. - */ - char *p = getenv("PLINK_PROTOCOL"); - if (p) { - const struct BackendVtable *vt = backend_vt_from_name(p); - if (vt) { - settings_set_default_protocol(vt->protocol); - settings_set_default_port(vt->default_port); - conf_set_int(conf, CONF_protocol, vt->protocol); - conf_set_int(conf, CONF_port, vt->default_port); - } - } - } + conf_set_bool(conf, CONF_agentfwd, FALSE); + conf_set_bool(conf, CONF_x11_forward, FALSE); + bool skipFurtherParameters = false; while (--argc) { char *p = *++argv; + if (p && !strcmp(p, "--")) { + skipFurtherParameters = true; + continue; + } int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), - 1, conf); + 1, conf, skipFurtherParameters); if (ret == -2) { fprintf(stderr, - "plink: option \"%s\" requires an argument\n", p); + "TortoisePlink: option \"%s\" requires an argument\n", p); errors = true; } else if (ret == 2) { --argc, ++argv; } else if (ret == 1) { continue; - } else if (!strcmp(p, "-batch")) { - console_batch_mode = true; - } else if (!strcmp(p, "-s")) { + } else if (!strcmp(p, "-batch") && !skipFurtherParameters) { + // ignore and do not print an error message + } else if (!strcmp(p, "-s") && !skipFurtherParameters) { /* Save status to write to conf later. */ use_subsystem = true; - } else if (!strcmp(p, "-V") || !strcmp(p, "--version")) { + } else if ((!strcmp(p, "-V") || !strcmp(p, "--version")) && !skipFurtherParameters) { version(); - } else if (!strcmp(p, "--help")) { + } else if (!strcmp(p, "--help") && !skipFurtherParameters) { usage(); - } else if (!strcmp(p, "-pgpfp")) { + } else if (!strcmp(p, "-pgpfp") && !skipFurtherParameters) { pgp_fingerprints(); exit(1); - } else if (!strcmp(p, "-shareexists")) { + } else if (!strcmp(p, "-shareexists") && !skipFurtherParameters) { just_test_share_exists = true; - } else if (!strcmp(p, "-sanitise-stdout") || - !strcmp(p, "-sanitize-stdout")) { + } else if ((!strcmp(p, "-sanitise-stdout") || + !strcmp(p, "-sanitize-stdout")) && !skipFurtherParameters) { sanitise_stdout = FORCE_ON; - } else if (!strcmp(p, "-no-sanitise-stdout") || - !strcmp(p, "-no-sanitize-stdout")) { + } else if ((!strcmp(p, "-no-sanitise-stdout") || + !strcmp(p, "-no-sanitize-stdout")) && !skipFurtherParameters) { sanitise_stdout = FORCE_OFF; - } else if (!strcmp(p, "-sanitise-stderr") || - !strcmp(p, "-sanitize-stderr")) { + } else if ((!strcmp(p, "-sanitise-stderr") || + !strcmp(p, "-sanitize-stderr")) && !skipFurtherParameters) { sanitise_stderr = FORCE_ON; - } else if (!strcmp(p, "-no-sanitise-stderr") || - !strcmp(p, "-no-sanitize-stderr")) { + } else if ((!strcmp(p, "-no-sanitise-stderr") || + !strcmp(p, "-no-sanitize-stderr")) && !skipFurtherParameters) { sanitise_stderr = FORCE_OFF; - } else if (!strcmp(p, "-no-antispoof")) { + } else if (!strcmp(p, "-no-antispoof") && !skipFurtherParameters) { console_antispoof_prompt = false; - } else if (*p != '-') { + } else if (*p != '-' || skipFurtherParameters) { strbuf *cmdbuf = strbuf_new(); while (argc > 0) { @@ -385,7 +393,7 @@ strbuf_free(cmdbuf); break; /* done with cmdline */ } else { - fprintf(stderr, "plink: unknown option \"%s\"\n", p); + fprintf(stderr, "TortoisePlink: unknown option \"%s\"\n", p); errors = true; } } @@ -423,7 +431,7 @@ if (vt->flags & BACKEND_NEEDS_TERMINAL) { fprintf(stderr, - "Plink doesn't support %s, which needs terminal emulation\n", + "TortoisePlink doesn't support %s, which needs terminal emulation\n", vt->displayname_lc); return 1; } @@ -430,7 +438,7 @@ sk_init(); if (p_WSAEventSelect == NULL) { - fprintf(stderr, "Plink requires WinSock 2\n"); + fprintf(stderr, "TortoisePlink requires WinSock 2\n"); return 1; }