Hi, Thanks for the patch, I've applied it slight changes. I had to re-add the undocumented support for extra arguments after the hostname - that's in the manpage now.
Cheers, Matt On Wed, Nov 11, 2015 at 07:02:36PM +0100, Guilhem Moulin wrote: > --- > cli-runopts.c | 202 > ++++++++++++++++++++++++++-------------------------------- > 1 file changed, 92 insertions(+), 110 deletions(-) > > diff --git a/cli-runopts.c b/cli-runopts.c > index 2b0cb7d..59ebb5a 100644 > --- a/cli-runopts.c > +++ b/cli-runopts.c > @@ -105,25 +105,30 @@ static void printhelp() { > void cli_getopts(int argc, char ** argv) { > unsigned int i, j; > char ** next = 0; > - unsigned int cmdlen; > + enum { > #ifdef ENABLE_CLI_PUBKEY_AUTH > - int nextiskey = 0; /* A flag if the next argument is a keyfile */ > + OPT_AUTHKEY, > #endif > #ifdef ENABLE_CLI_LOCALTCPFWD > - int nextislocal = 0; > + OPT_LOCALTCPFWD, > #endif > #ifdef ENABLE_CLI_REMOTETCPFWD > - int nextisremote = 0; > + OPT_REMOTETCPFWD, > #endif > #ifdef ENABLE_CLI_NETCAT > - int nextisnetcat = 0; > + OPT_NETCAT, > #endif > + /* a flag (no arg) if 'next' is NULL, a string-valued option > otherwise */ > + OPT_OTHER > + } opt; > + unsigned int cmdlen; > char* dummy = NULL; /* Not used for anything real */ > > char* recv_window_arg = NULL; > char* keepalive_arg = NULL; > char* idle_timeout_arg = NULL; > char *host_arg = NULL; > + char c; > > /* see printhelp() for options */ > cli_opts.progname = argv[0]; > @@ -172,58 +177,8 @@ void cli_getopts(int argc, char ** argv) { > > fill_own_user(); > > - /* Iterate all the arguments */ > - for (i = 1; i < (unsigned int)argc; i++) { > -#ifdef ENABLE_CLI_PUBKEY_AUTH > - if (nextiskey) { > - /* Load a hostkey since the previous argument was "-i" > */ > - loadidentityfile(argv[i], 1); > - nextiskey = 0; > - continue; > - } > -#endif > -#ifdef ENABLE_CLI_REMOTETCPFWD > - if (nextisremote) { > - TRACE(("nextisremote true")) > - addforward(argv[i], cli_opts.remotefwds); > - nextisremote = 0; > - continue; > - } > -#endif > -#ifdef ENABLE_CLI_LOCALTCPFWD > - if (nextislocal) { > - TRACE(("nextislocal true")) > - addforward(argv[i], cli_opts.localfwds); > - nextislocal = 0; > - continue; > - } > -#endif > -#ifdef ENABLE_CLI_NETCAT > - if (nextisnetcat) { > - TRACE(("nextisnetcat true")) > - add_netcat(argv[i]); > - nextisnetcat = 0; > - continue; > - } > -#endif > - if (next) { > - /* The previous flag set a value to assign */ > - *next = argv[i]; > - if (*next == NULL) { > - dropbear_exit("Invalid null argument"); > - } > - next = NULL; > - continue; > - } > - > - if (argv[i][0] == '-') { > - /* A flag *waves* */ > - char c = argv[i][1]; > - if (strlen(argv[i]) != 2) { > - /* We only handle one flag per hyphen */ > - fprintf(stderr, "Warning, trailing '%s' of '%s' > is ignored.\n", > - &argv[i][2], argv[i]); > - } > + for (i = 1; i < (unsigned int)argc && argv[i][0] == '-'; i++) { > + for (j = 1; (c = argv[i][j]) != '\0' && !next && opt == > OPT_OTHER; j++) { > switch (c) { > case 'y': /* always accept the remote hostkey */ > if (cli_opts.always_accept_key) { > @@ -237,12 +192,7 @@ void cli_getopts(int argc, char ** argv) { > break; > #ifdef ENABLE_CLI_PUBKEY_AUTH > case 'i': /* an identityfile */ > - /* Keep scp happy when it changes "-i > file" to "-ifile" */ > - if (strlen(argv[i]) > 2) { > - loadidentityfile(&argv[i][2], > 1); > - } else { > - nextiskey = 1; > - } > + opt = OPT_AUTHKEY; > break; > #endif > case 't': /* we want a pty */ > @@ -262,7 +212,7 @@ void cli_getopts(int argc, char ** argv) { > break; > #ifdef ENABLE_CLI_LOCALTCPFWD > case 'L': > - nextislocal = 1; > + opt = OPT_LOCALTCPFWD; > break; > case 'g': > opts.listen_fwd_all = 1; > @@ -270,12 +220,12 @@ void cli_getopts(int argc, char ** argv) { > #endif > #ifdef ENABLE_CLI_REMOTETCPFWD > case 'R': > - nextisremote = 1; > + opt = OPT_REMOTETCPFWD; > break; > #endif > #ifdef ENABLE_CLI_NETCAT > case 'B': > - nextisnetcat = 1; > + opt = OPT_NETCAT; > break; > #endif > #ifdef ENABLE_CLI_PROXYCMD > @@ -341,50 +291,87 @@ void cli_getopts(int argc, char ** argv) { > case 'b': > next = &dummy; > default: > - fprintf(stderr, > - "WARNING: Ignoring unknown > argument '%s'\n", argv[i]); > + fprintf(stderr, > + "WARNING: Ignoring unknown > option -%c\n", c); > break; > } /* Switch */ > - > - /* Now we handle args where they might be "-luser" (no > spaces)*/ > - if (next && strlen(argv[i]) > 2) { > - *next = &argv[i][2]; > - next = NULL; > - } > + } > > - continue; /* next argument */ > + if (!next && opt == OPT_OTHER) /* got a flag */ > + continue; > > - } else { > - TRACE(("non-flag arg: '%s'", argv[i])) > - > - /* Either the hostname or commands */ > - > - if (host_arg == NULL) { > - host_arg = argv[i]; > - } else { > - > - /* this is part of the commands to send - after > this we > - * don't parse any more options, and flags are > sent as the > - * command */ > - cmdlen = 0; > - for (j = i; j < (unsigned int)argc; j++) { > - cmdlen += strlen(argv[j]) + 1; /* +1 > for spaces */ > - } > - /* Allocate the space */ > - cli_opts.cmd = (char*)m_malloc(cmdlen); > - cli_opts.cmd[0] = '\0'; > - > - /* Append all the bits */ > - for (j = i; j < (unsigned int)argc; j++) { > - strlcat(cli_opts.cmd, argv[j], cmdlen); > - strlcat(cli_opts.cmd, " ", cmdlen); > - } > - /* It'll be null-terminated here */ > - > - /* We've eaten all the options and flags */ > - break; > - } > + if (c == '\0') { > + i++; > + j = 0; > + if (!argv[i]) > + dropbear_exit("Missing argument"); > } > + > +#ifdef ENABLE_CLI_PUBKEY_AUTH > + if (opt == OPT_AUTHKEY) { > + TRACE(("opt authkey")) > + loadidentityfile(&argv[i][j], 1); > + } > + else > +#endif > +#ifdef ENABLE_CLI_REMOTETCPFWD > + if (opt == OPT_REMOTETCPFWD) { > + TRACE(("opt remotetcpfwd")) > + addforward(&argv[i][j], cli_opts.remotefwds); > + } > + else > +#endif > +#ifdef ENABLE_CLI_LOCALTCPFWD > + if (opt == OPT_LOCALTCPFWD) { > + TRACE(("opt localtcpfwd")) > + addforward(&argv[i][j], cli_opts.localfwds); > + } > + else > +#endif > +#ifdef ENABLE_CLI_NETCAT > + if (opt == OPT_NETCAT) { > + TRACE(("opt netcat")) > + add_netcat(&argv[i][j]); > + } > + else > +#endif > + if (next) { > + /* The previous flag set a value to assign */ > + *next = &argv[i][j]; > + if (*next == NULL) > + dropbear_exit("Invalid null argument"); > + next = NULL; > + } > + opt = OPT_OTHER; > + } > + > + /* Done with options/flags; now handle the hostname (which may not > + * start with a hyphen) and optional command */ > + > + if (i >= (unsigned int)argc) { /* missing hostname */ > + printhelp(); > + exit(EXIT_FAILURE); > + } > + host_arg = argv[i++]; > + TRACE(("host is: %s", host_arg)) > + > + if (i < (unsigned int)argc) { > + /* Build the command to send */ > + cmdlen = 0; > + for (j = i; j < (unsigned int)argc; j++) > + cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */ > + > + /* Allocate the space */ > + cli_opts.cmd = (char*)m_malloc(cmdlen); > + cli_opts.cmd[0] = '\0'; > + > + /* Append all the bits */ > + for (j = i; j < (unsigned int)argc; j++) { > + strlcat(cli_opts.cmd, argv[j], cmdlen); > + strlcat(cli_opts.cmd, " ", cmdlen); > + } > + /* It'll be null-terminated here */ > + TRACE(("cmd is: %s", cli_opts.cmd)) > } > > /* And now a few sanity checks and setup */ > @@ -393,11 +380,6 @@ void cli_getopts(int argc, char ** argv) { > parse_ciphers_macs(); > #endif > > - if (host_arg == NULL) { > - printhelp(); > - exit(EXIT_FAILURE); > - } > - > #ifdef ENABLE_CLI_PROXYCMD > > > if (cli_opts.proxycmd) { > /* To match the common path of m_freeing it */ > -- > 2.6.2 >