[PATCH] Enable bundling for dbclient.

Matt Johnston matt at ucc.asn.au
Mon Nov 23 23:04:19 AWST 2015


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
> 


More information about the Dropbear mailing list