- (djm) Big OpenBSD sync:
   - markus@cvs.openbsd.org  2000/09/30 10:27:44
     [log.c]
     allow loglevel debug
   - markus@cvs.openbsd.org  2000/10/03 11:59:57
     [packet.c]
     hmac->mac
   - markus@cvs.openbsd.org  2000/10/03 12:03:03
     [auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c]
     move fake-auth from auth1.c to individual auth methods, disables s/key in
     debug-msg
   - markus@cvs.openbsd.org  2000/10/03 12:16:48
     ssh.c
     do not resolve canonname, i have no idea why this was added oin ossh
   - markus@cvs.openbsd.org  2000/10/09 15:30:44
     ssh-keygen.1 ssh-keygen.c
     -X now reads private ssh.com DSA keys, too.
   - markus@cvs.openbsd.org  2000/10/09 15:32:34
     auth-options.c
     clear options on every call.
   - markus@cvs.openbsd.org  2000/10/09 15:51:00
     authfd.c authfd.h
     interop with ssh-agent2, from <res@shore.net>
   - markus@cvs.openbsd.org  2000/10/10 14:20:45
     compat.c
     use rexexp for version string matching
   - provos@cvs.openbsd.org  2000/10/10 22:02:18
     [kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h]
     First rough implementation of the diffie-hellman group exchange.  The
     client can ask the server for bigger groups to perform the diffie-hellman
     in, thus increasing the attack complexity when using ciphers with longer
     keys.  University of Windsor provided network, T the company.
   - markus@cvs.openbsd.org  2000/10/11 13:59:52
     [auth-rsa.c auth2.c]
     clear auth options unless auth sucessfull
   - markus@cvs.openbsd.org  2000/10/11 14:00:27
     [auth-options.h]
     clear auth options unless auth sucessfull
   - markus@cvs.openbsd.org  2000/10/11 14:03:27
     [scp.1 scp.c]
     support 'scp -o' with help from mouring@pconline.com
   - markus@cvs.openbsd.org  2000/10/11 14:11:35
     [dh.c]
     Wall
   - markus@cvs.openbsd.org  2000/10/11 14:14:40
     [auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h]
     [ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h]
     add support for s/key (kbd-interactive) to ssh2, based on work by
     mkiernan@avantgo.com and me
   - markus@cvs.openbsd.org  2000/10/11 14:27:24
     [auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h]
     [myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c]
     [sshconnect2.c sshd.c]
     new cipher framework
   - markus@cvs.openbsd.org  2000/10/11 14:45:21
     [cipher.c]
     remove DES
   - markus@cvs.openbsd.org  2000/10/12 03:59:20
     [cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c]
     enable DES in SSH-1 clients only
   - markus@cvs.openbsd.org  2000/10/12 08:21:13
     [kex.h packet.c]
     remove unused
   - markus@cvs.openbsd.org  2000/10/13 12:34:46
     [sshd.c]
     Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se
   - markus@cvs.openbsd.org  2000/10/13 12:59:15
     [cipher.c cipher.h myproposal.h  rijndael.c rijndael.h]
     rijndael/aes support
   - markus@cvs.openbsd.org  2000/10/13 13:10:54
     [sshd.8]
     more info about -V
   - markus@cvs.openbsd.org  2000/10/13 13:12:02
     [myproposal.h]
     prefer no compression
diff --git a/scp.c b/scp.c
index 356d97e..40cf729 100644
--- a/scp.c
+++ b/scp.c
@@ -75,7 +75,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: scp.c,v 1.40 2000/09/21 11:11:42 markus Exp $");
+RCSID("$OpenBSD: scp.c,v 1.41 2000/10/11 20:03:27 markus Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -102,6 +102,9 @@
 int getttywidth(void);
 int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);
 
+/* setup arguments for the call to ssh */
+void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+
 /* Time a transfer started. */
 static struct timeval start;
 
@@ -114,12 +117,6 @@
 /* Name of current file being transferred. */
 char *curfile;
 
-/* This is set to non-zero if IPv4 is desired. */
-int IPv4 = 0;
-
-/* This is set to non-zero if IPv6 is desired. */
-int IPv6 = 0;
-
 /* This is set to non-zero to enable verbose mode. */
 int verbose_mode = 0;
 
@@ -129,23 +126,16 @@
 /* This is set to zero if the progressmeter is not desired. */
 int showprogress = 1;
 
-/* This is set to non-zero if running in batch mode (that is, password
-   and passphrase queries are not allowed). */
-int batchmode = 0;
-
-/* This is set to the cipher type string if given on the command line. */
-char *cipher = NULL;
-
-/* This is set to the RSA authentication identity file name if given on
-   the command line. */
-char *identity = NULL;
-
-/* This is the port to use in contacting the remote site (is non-NULL). */
-char *port = NULL;
-
 /* This is the program to execute for the secured connection. ("ssh" or -S) */
 char *ssh_program = SSH_PROGRAM;
 
+/* This is the list of arguments that scp passes to ssh */
+struct {
+	char	**list;
+	int	num;
+	int	nalloc;
+} args;
+
 /*
  * This function executes the given command as the specified user on the
  * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
@@ -158,8 +148,8 @@
 	int pin[2], pout[2], reserved[2];
 
 	if (verbose_mode)
-		fprintf(stderr, "Executing: host %s, user %s, command %s\n",
-		    host, remuser ? remuser : "(unspecified)", cmd);
+		fprintf(stderr, "Executing: program %s host %s, user %s, command %s\n",
+		    ssh_program, host, remuser ? remuser : "(unspecified)", cmd);
 
 	/*
 	 * Reserve two descriptors so that the real pipes won't get
@@ -178,10 +168,7 @@
 	close(reserved[1]);
 
 	/* For a child to execute the command on the remote host using ssh. */
-	if (fork() == 0) {
-		char *args[100];	/* XXX careful */
-		unsigned int i;
-
+	if (fork() == 0)  {
 		/* Child. */
 		close(pin[1]);
 		close(pout[0]);
@@ -190,41 +177,13 @@
 		close(pin[0]);
 		close(pout[1]);
 
-		i = 0;
-		args[i++] = ssh_program;
-		args[i++] = "-x";
-		args[i++] = "-oFallBackToRsh no";
-		if (IPv4)
-			args[i++] = "-4";
-		if (IPv6)
-			args[i++] = "-6";
-		if (verbose_mode)
-			args[i++] = "-v";
-		if (compress_flag)
-			args[i++] = "-C";
-		if (batchmode)
-			args[i++] = "-oBatchMode yes";
-		if (cipher != NULL) {
-			args[i++] = "-c";
-			args[i++] = cipher;
-		}
-		if (identity != NULL) {
-			args[i++] = "-i";
-			args[i++] = identity;
-		}
-		if (port != NULL) {
-			args[i++] = "-p";
-			args[i++] = port;
-		}
-		if (remuser != NULL) {
-			args[i++] = "-l";
-			args[i++] = remuser;
-		}
-		args[i++] = host;
-		args[i++] = cmd;
-		args[i++] = NULL;
+		args.list[0] = ssh_program;
+		if (remuser != NULL)
+			addargs("-l %s", remuser);
+		addargs("%s", host);
+		addargs("%s", cmd);
 
-		execvp(ssh_program, args);
+		execvp(ssh_program, args.list);
 		perror(ssh_program);
 		exit(1);
 	}
@@ -290,27 +249,45 @@
 	extern char *optarg;
 	extern int optind;
 
+	args.list = NULL;
+	addargs("ssh");	 	/* overwritten with ssh_program */
+	addargs("-x");
+	addargs("-oFallBackToRsh no");
+
 	fflag = tflag = 0;
-	while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:")) != EOF)
+	while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF)
 		switch (ch) {
 		/* User-visible flags. */
 		case '4':
-			IPv4 = 1;
-			break;
 		case '6':
-			IPv6 = 1;
+		case 'C':
+			addargs("-%c", ch);
+			break;
+		case 'o':
+		case 'c':
+		case 'i':
+			addargs("-%c %s", ch, optarg);
+			break;
+		case 'P':
+			addargs("-p %s", optarg);
+			break;
+		case 'B':
+			addargs("-o Batchmode yes");
 			break;
 		case 'p':
 			pflag = 1;
 			break;
-		case 'P':
-			port = optarg;
-			break;
 		case 'r':
 			iamrecursive = 1;
 			break;
 		case 'S':
-			ssh_program = optarg;
+			ssh_program = xstrdup(optarg);
+			break;
+		case 'v':
+			verbose_mode = 1;
+			break;
+		case 'q':
+			showprogress = 0;
 			break;
 
 		/* Server options. */
@@ -325,24 +302,6 @@
 			iamremote = 1;
 			tflag = 1;
 			break;
-		case 'c':
-			cipher = optarg;
-			break;
-		case 'i':
-			identity = optarg;
-			break;
-		case 'v':
-			verbose_mode = 1;
-			break;
-		case 'B':
-			batchmode = 1;
-			break;
-		case 'C':
-			compress_flag = 1;
-			break;
-		case 'q':
-			showprogress = 0;
-			break;
 		case '?':
 		default:
 			usage();
@@ -1287,3 +1246,25 @@
 	else
 		return (80);
 }
+
+void
+addargs(char *fmt, ...)
+{
+	va_list ap;
+	char buf[1024];
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+
+	if (args.list == NULL) {
+		args.nalloc = 32;
+		args.num = 0;
+		args.list = xmalloc(args.nalloc * sizeof(char *));
+	} else if (args.num+2 >= args.nalloc) {
+		args.nalloc *= 2;
+		args.list = xrealloc(args.list, args.nalloc * sizeof(char *));
+	}
+	args.list[args.num++] = xstrdup(buf);
+	args.list[args.num] = NULL;
+}