Revamp SSH authentication code so that user interaction is more
[u/mdw/putty] / pscp.c
diff --git a/pscp.c b/pscp.c
index 1c601e9..575025f 100644 (file)
--- a/pscp.c
+++ b/pscp.c
@@ -213,8 +213,6 @@ int from_backend(void *frontend, int is_stderr, const char *data, int datalen)
        if (pendsize < pendlen + len) {
            pendsize = pendlen + len + 4096;
            pending = sresize(pending, pendsize, unsigned char);
-           if (!pending)
-               fatalbox("Out of memory");
        }
        memcpy(pending + pendlen, p, len);
        pendlen += len;
@@ -222,6 +220,15 @@ int from_backend(void *frontend, int is_stderr, const char *data, int datalen)
 
     return 0;
 }
+int from_backend_untrusted(void *frontend_handle, const char *data, int len)
+{
+    /*
+     * No "untrusted" output should get here (the way the code is
+     * currently, it's all diverted by FLAG_STDERR).
+     */
+    assert(!"Unexpected call to from_backend_untrusted()");
+    return 0; /* not reached */
+}
 static int ssh_scp_recv(unsigned char *buf, int len)
 {
     outptr = buf;
@@ -322,6 +329,17 @@ static void do_cmd(char *host, char *user, char *cmd)
        bump("Empty host name");
 
     /*
+     * Remove fiddly bits of address: remove a colon suffix, and
+     * the square brackets around an IPv6 literal address.
+     */
+    if (host[0] == '[') {
+       host++;
+       host[strcspn(host, "]")] = '\0';
+    } else {
+       host[strcspn(host, ":")] = '\0';
+    }
+
+    /*
      * If we haven't loaded session details already (e.g., from -load),
      * try looking for a session called "host".
      */
@@ -382,11 +400,6 @@ static void do_cmd(char *host, char *user, char *cmd)
     }
 
     /*
-     * Trim a colon suffix off the hostname if it's there.
-     */
-    cfg.host[strcspn(cfg.host, ":")] = '\0';
-
-    /*
      * Remove any remaining whitespace from the hostname.
      */
     {
@@ -533,6 +546,19 @@ static void print_stats(char *name, unsigned long size, unsigned long done,
  */
 static char *colon(char *str)
 {
+    /* Check and process IPv6 literal addresses
+     * (eg: 'jeroen@[2001:db8::1]:myfile.txt') */
+    char *ipv6 = strchr(str, '[');
+    if (ipv6) {
+       str = strchr(str, ']');
+       if (str) {
+           /* Terminate on the closing bracket */
+           *str++ = '\0';
+           return (str);
+       }
+       return (NULL);
+    }
+
     /* We ignore a leading colon, since the hostname cannot be
        empty. We also ignore a colon as second character because
        of filenames like f:myfile.txt. */
@@ -687,7 +713,6 @@ void scp_sftp_listdir(char *dirname)
 
            for (i = 0; i < names->nnames; i++)
                ournames[nnames++] = names->names[i];
-
            names->nnames = 0;         /* prevent free_names */
            fxp_free_names(names);
        }
@@ -733,7 +758,7 @@ static struct fxp_handle *scp_sftp_filehandle;
 static struct fxp_xfer *scp_sftp_xfer;
 static uint64 scp_sftp_fileoffset;
 
-void scp_source_setup(char *target, int shouldbedir)
+int scp_source_setup(char *target, int shouldbedir)
 {
     if (using_sftp) {
        /*
@@ -748,7 +773,7 @@ void scp_source_setup(char *target, int shouldbedir)
        if (!fxp_init()) {
            tell_user(stderr, "unable to initialise SFTP: %s", fxp_error());
            errs++;
-           return;
+           return 1;
        }
 
        sftp_register(req = fxp_stat_send(target));
@@ -771,6 +796,7 @@ void scp_source_setup(char *target, int shouldbedir)
     } else {
        (void) response();
     }
+    return 0;
 }
 
 int scp_send_errmsg(char *str)
@@ -1289,8 +1315,21 @@ int scp_get_sink_action(struct scp_sink_action *act)
                    namesize += names->nnames + 128;
                    ournames = sresize(ournames, namesize, struct fxp_name);
                }
-               for (i = 0; i < names->nnames; i++)
-                   ournames[nnames++] = names->names[i];
+               for (i = 0; i < names->nnames; i++) {
+                   if (!strcmp(names->names[i].filename, ".") ||
+                       !strcmp(names->names[i].filename, "..")) {
+                       /*
+                        * . and .. are normal consequences of
+                        * reading a directory, and aren't worth
+                        * complaining about.
+                        */
+                   } else if (!vet_filename(names->names[i].filename)) {
+                       tell_user(stderr, "ignoring potentially dangerous server-"
+                                 "supplied filename '%s'\n",
+                                 names->names[i].filename);
+                   } else
+                       ournames[nnames++] = names->names[i];
+               }
                names->nnames = 0;             /* prevent free_names */
                fxp_free_names(names);
            }
@@ -1796,7 +1835,7 @@ static void sink(char *targ, char *src)
                    tell_user(stderr, "         when we requested a file "
                              "called '%s'.", stripsrc);
                    tell_user(stderr, "         If this is a wildcard, "
-                             "consider upgrading to SSH 2 or using");
+                             "consider upgrading to SSH-2 or using");
                    tell_user(stderr, "         the '-unsafe' option. Renaming"
                              " of this file has been disallowed.");
                    /* Override the name the server provided with our own. */
@@ -1916,7 +1955,7 @@ static void toremote(int argc, char *argv[])
     *targ++ = '\0';
     if (*targ == '\0')
        targ = ".";
-    /* Substitute "." for emtpy target */
+    /* Substitute "." for empty target */
 
     /* Separate host and username */
     user = host;
@@ -1949,7 +1988,8 @@ static void toremote(int argc, char *argv[])
     do_cmd(host, user, cmd);
     sfree(cmd);
 
-    scp_source_setup(targ, targetshouldbedirectory);
+    if (scp_source_setup(targ, targetshouldbedirectory))
+       return;
 
     for (i = 0; i < argc - 1; i++) {
        src = argv[i];
@@ -2108,6 +2148,8 @@ static void usage(void)
        ("       pscp [options] source [source...] [user@]host:target\n");
     printf("       pscp [options] -ls [user@]host:filespec\n");
     printf("Options:\n");
+    printf("  -V        print version information and exit\n");
+    printf("  -pgpfp    print PGP key fingerprints and exit\n");
     printf("  -p        preserve file attributes\n");
     printf("  -q        quiet, don't show statistics\n");
     printf("  -r        copy directories recursively\n");
@@ -2117,11 +2159,11 @@ static void usage(void)
     printf("  -l user   connect with specified username\n");
     printf("  -pw passw login with specified password\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 authentication\n");
     printf("  -batch    disable all interactive prompts\n");
     printf("  -unsafe   allow server-side wildcards (DANGEROUS)\n");
-    printf("  -V        print version information\n");
     printf("  -sftp     force use of SFTP protocol\n");
     printf("  -scp      force use of SCP protocol\n");
 #if 0
@@ -2171,7 +2213,6 @@ int psftp_main(int argc, char *argv[])
 #endif
        ;
     cmdline_tooltype = TOOLTYPE_FILETRANSFER;
-    ssh_get_line = &console_get_line;
     sk_init();
 
     /* Load Default Settings before doing anything else. */
@@ -2191,6 +2232,9 @@ int psftp_main(int argc, char *argv[])
            /* We have our own verbosity in addition to `flags'. */
            if (flags & FLAG_VERBOSE)
                verbose = 1;
+        } else if (strcmp(argv[i], "-pgpfp") == 0) {
+            pgp_fingerprints();
+            return 1;
        } else if (strcmp(argv[i], "-r") == 0) {
            recursive = 1;
        } else if (strcmp(argv[i], "-p") == 0) {