]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - scp.c
Retired the #ifdef DUMP_PACKETS stuff in ssh.c because I'm utterly
[PuTTY.git] / scp.c
1 /*
2  * scp.c  -  Scp (Secure Copy) client for PuTTY.
3  * Joris van Rantwijk, Simon Tatham
4  *
5  * This is mainly based on ssh-1.2.26/scp.c by Timo Rinne & Tatu Ylonen.
6  * They, in turn, used stuff from BSD rcp.
7  * 
8  * (SGT, 2001-09-10: Joris van Rantwijk assures me that although
9  * this file as originally submitted was inspired by, and
10  * _structurally_ based on, ssh-1.2.26's scp.c, there wasn't any
11  * actual code duplicated, so the above comment shouldn't give rise
12  * to licensing issues.)
13  */
14
15 #include <windows.h>
16 #ifndef AUTO_WINSOCK
17 #ifdef WINSOCK_TWO
18 #include <winsock2.h>
19 #else
20 #include <winsock.h>
21 #endif
22 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <time.h>
28 #include <assert.h>
29
30 #define PUTTY_DO_GLOBALS
31 #include "putty.h"
32 #include "ssh.h"
33 #include "sftp.h"
34 #include "winstuff.h"
35 #include "storage.h"
36
37 #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
38         ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
39 #define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
40         ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
41
42 /* GUI Adaptation - Sept 2000 */
43 #define   WM_APP_BASE           0x8000
44 #define   WM_STD_OUT_CHAR       ( WM_APP_BASE+400 )
45 #define   WM_STD_ERR_CHAR       ( WM_APP_BASE+401 )
46 #define   WM_STATS_CHAR         ( WM_APP_BASE+402 )
47 #define   WM_STATS_SIZE         ( WM_APP_BASE+403 )
48 #define   WM_STATS_PERCENT      ( WM_APP_BASE+404 )
49 #define   WM_STATS_ELAPSED      ( WM_APP_BASE+405 )
50 #define   WM_RET_ERR_CNT        ( WM_APP_BASE+406 )
51 #define   WM_LS_RET_ERR_CNT     ( WM_APP_BASE+407 )
52 #define   WM_STATS_DONE         ( WM_APP_BASE+408 )
53 #define   WM_STATS_ETA          ( WM_APP_BASE+409 )
54 #define   WM_STATS_RATEBS       ( WM_APP_BASE+410 )
55
56 static int list = 0;
57 static int verbose = 0;
58 static int recursive = 0;
59 static int preserve = 0;
60 static int targetshouldbedirectory = 0;
61 static int statistics = 1;
62 static int portnumber = 0;
63 static int prev_stats_len = 0;
64 static int scp_unsafe_mode = 0;
65 static char *password = NULL;
66 static int errs = 0;
67 /* GUI Adaptation - Sept 2000 */
68 #define NAME_STR_MAX 2048
69 static char statname[NAME_STR_MAX + 1];
70 static unsigned long statsize = 0;
71 static unsigned long statdone = 0;
72 static unsigned long stateta = 0;
73 static unsigned long statratebs = 0;
74 static int statperct = 0;
75 static unsigned long statelapsed = 0;
76 static int gui_mode = 0;
77 static char *gui_hwnd = NULL;
78 static int using_sftp = 0;
79
80 static void source(char *src);
81 static void rsource(char *src);
82 static void sink(char *targ, char *src);
83 /* GUI Adaptation - Sept 2000 */
84 static void tell_char(FILE * stream, char c);
85 static void tell_str(FILE * stream, char *str);
86 static void tell_user(FILE * stream, char *fmt, ...);
87 static void gui_update_stats(char *name, unsigned long size,
88                              int percentage, unsigned long elapsed, 
89                              unsigned long done, unsigned long eta,
90                              unsigned long ratebs);
91
92 /*
93  * The maximum amount of queued data we accept before we stop and
94  * wait for the server to process some.
95  */
96 #define MAX_SCP_BUFSIZE 16384
97
98 void logevent(char *string)
99 {
100 }
101
102 void ldisc_send(char *buf, int len, int interactive)
103 {
104     /*
105      * This is only here because of the calls to ldisc_send(NULL,
106      * 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc
107      * as an ldisc. So if we get called with any real data, I want
108      * to know about it.
109      */
110     assert(len == 0);
111 }
112
113 void verify_ssh_host_key(char *host, int port, char *keytype,
114                          char *keystr, char *fingerprint)
115 {
116     int ret;
117     HANDLE hin;
118     DWORD savemode, i;
119
120     static const char absentmsg[] =
121         "The server's host key is not cached in the registry. You\n"
122         "have no guarantee that the server is the computer you\n"
123         "think it is.\n"
124         "The server's key fingerprint is:\n"
125         "%s\n"
126         "If you trust this host, enter \"y\" to add the key to\n"
127         "PuTTY's cache and carry on connecting.\n"
128         "If you want to carry on connecting just once, without\n"
129         "adding the key to the cache, enter \"n\".\n"
130         "If you do not trust this host, press Return to abandon the\n"
131         "connection.\n"
132         "Store key in cache? (y/n) ";
133
134     static const char wrongmsg[] =
135         "WARNING - POTENTIAL SECURITY BREACH!\n"
136         "The server's host key does not match the one PuTTY has\n"
137         "cached in the registry. This means that either the\n"
138         "server administrator has changed the host key, or you\n"
139         "have actually connected to another computer pretending\n"
140         "to be the server.\n"
141         "The new key fingerprint is:\n"
142         "%s\n"
143         "If you were expecting this change and trust the new key,\n"
144         "enter \"y\" to update PuTTY's cache and continue connecting.\n"
145         "If you want to carry on connecting but without updating\n"
146         "the cache, enter \"n\".\n"
147         "If you want to abandon the connection completely, press\n"
148         "Return to cancel. Pressing Return is the ONLY guaranteed\n"
149         "safe choice.\n"
150         "Update cached key? (y/n, Return cancels connection) ";
151
152     static const char abandoned[] = "Connection abandoned.\n";
153
154     char line[32];
155
156     /*
157      * Verify the key against the registry.
158      */
159     ret = verify_host_key(host, port, keytype, keystr);
160
161     if (ret == 0)                      /* success - key matched OK */
162         return;
163
164     if (ret == 2) {                    /* key was different */
165         fprintf(stderr, wrongmsg, fingerprint);
166         fflush(stderr);
167     }
168     if (ret == 1) {                    /* key was absent */
169         fprintf(stderr, absentmsg, fingerprint);
170         fflush(stderr);
171     }
172
173     hin = GetStdHandle(STD_INPUT_HANDLE);
174     GetConsoleMode(hin, &savemode);
175     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
176                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
177     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
178     SetConsoleMode(hin, savemode);
179
180     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
181         if (line[0] == 'y' || line[0] == 'Y')
182             store_host_key(host, port, keytype, keystr);
183     } else {
184         fprintf(stderr, abandoned);
185         exit(0);
186     }
187 }
188
189 /*
190  * Ask whether the selected cipher is acceptable (since it was
191  * below the configured 'warn' threshold).
192  * cs: 0 = both ways, 1 = client->server, 2 = server->client
193  */
194 void askcipher(char *ciphername, int cs)
195 {
196     HANDLE hin;
197     DWORD savemode, i;
198
199     static const char msg[] =
200         "The first %scipher supported by the server is\n"
201         "%s, which is below the configured warning threshold.\n"
202         "Continue with connection? (y/n) ";
203     static const char abandoned[] = "Connection abandoned.\n";
204
205     char line[32];
206
207     fprintf(stderr, msg,
208             (cs == 0) ? "" :
209             (cs == 1) ? "client-to-server " :
210                         "server-to-client ",
211             ciphername);
212     fflush(stderr);
213
214     hin = GetStdHandle(STD_INPUT_HANDLE);
215     GetConsoleMode(hin, &savemode);
216     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
217                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
218     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
219     SetConsoleMode(hin, savemode);
220
221     if (line[0] == 'y' || line[0] == 'Y') {
222         return;
223     } else {
224         fprintf(stderr, abandoned);
225         exit(0);
226     }
227 }
228
229 /*
230  * Ask whether to wipe a session log file before writing to it.
231  * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
232  */
233 int askappend(char *filename)
234 {
235     HANDLE hin;
236     DWORD savemode, i;
237
238     static const char msgtemplate[] =
239         "The session log file \"%.*s\" already exists.\n"
240         "You can overwrite it with a new session log,\n"
241         "append your session log to the end of it,\n"
242         "or disable session logging for this session.\n"
243         "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
244         "or just press Return to disable logging.\n"
245         "Wipe the log file? (y/n, Return cancels logging) ";
246
247     char line[32];
248
249     fprintf(stderr, msgtemplate, FILENAME_MAX, filename);
250     fflush(stderr);
251
252     hin = GetStdHandle(STD_INPUT_HANDLE);
253     GetConsoleMode(hin, &savemode);
254     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
255                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
256     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
257     SetConsoleMode(hin, savemode);
258
259     if (line[0] == 'y' || line[0] == 'Y')
260         return 2;
261     else if (line[0] == 'n' || line[0] == 'N')
262         return 1;
263     else
264         return 0;
265 }
266
267 /*
268  * Warn about the obsolescent key file format.
269  */
270 void old_keyfile_warning(void)
271 {
272     static const char message[] =
273         "You are loading an SSH 2 private key which has an\n"
274         "old version of the file format. This means your key\n"
275         "file is not fully tamperproof. Future versions of\n"
276         "PuTTY may stop supporting this private key format,\n"
277         "so we recommend you convert your key to the new\n"
278         "format.\n"
279         "\n"
280         "Once the key is loaded into PuTTYgen, you can perform\n"
281         "this conversion simply by saving it again.\n";
282
283     fputs(message, stderr);
284 }
285
286 /* GUI Adaptation - Sept 2000 */
287 static void send_msg(HWND h, UINT message, WPARAM wParam)
288 {
289     while (!PostMessage(h, message, wParam, 0))
290         SleepEx(1000, TRUE);
291 }
292
293 static void tell_char(FILE * stream, char c)
294 {
295     if (!gui_mode)
296         fputc(c, stream);
297     else {
298         unsigned int msg_id = WM_STD_OUT_CHAR;
299         if (stream == stderr)
300             msg_id = WM_STD_ERR_CHAR;
301         send_msg((HWND) atoi(gui_hwnd), msg_id, (WPARAM) c);
302     }
303 }
304
305 static void tell_str(FILE * stream, char *str)
306 {
307     unsigned int i;
308
309     for (i = 0; i < strlen(str); ++i)
310         tell_char(stream, str[i]);
311 }
312
313 static void tell_user(FILE * stream, char *fmt, ...)
314 {
315     char str[0x100];                   /* Make the size big enough */
316     va_list ap;
317     va_start(ap, fmt);
318     vsprintf(str, fmt, ap);
319     va_end(ap);
320     strcat(str, "\n");
321     tell_str(stream, str);
322 }
323
324 static void gui_update_stats(char *name, unsigned long size,
325                              int percentage, unsigned long elapsed,
326                              unsigned long done, unsigned long eta,
327                              unsigned long ratebs)
328 {
329     unsigned int i;
330
331     if (strcmp(name, statname) != 0) {
332         for (i = 0; i < strlen(name); ++i)
333             send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR,
334                      (WPARAM) name[i]);
335         send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR, (WPARAM) '\n');
336         strcpy(statname, name);
337     }
338     if (statsize != size) {
339         send_msg((HWND) atoi(gui_hwnd), WM_STATS_SIZE, (WPARAM) size);
340         statsize = size;
341     }
342     if (statdone != done) {
343         send_msg((HWND) atoi(gui_hwnd), WM_STATS_DONE, (WPARAM) done);
344         statdone = done;
345     }
346     if (stateta != eta) {
347         send_msg((HWND) atoi(gui_hwnd), WM_STATS_ETA, (WPARAM) eta);
348         stateta = eta;
349     }
350     if (statratebs != ratebs) {
351         send_msg((HWND) atoi(gui_hwnd), WM_STATS_RATEBS, (WPARAM) ratebs);
352         statratebs = ratebs;
353     }
354     if (statelapsed != elapsed) {
355         send_msg((HWND) atoi(gui_hwnd), WM_STATS_ELAPSED,
356                  (WPARAM) elapsed);
357         statelapsed = elapsed;
358     }
359     if (statperct != percentage) {
360         send_msg((HWND) atoi(gui_hwnd), WM_STATS_PERCENT,
361                  (WPARAM) percentage);
362         statperct = percentage;
363     }
364 }
365
366 /*
367  *  Print an error message and perform a fatal exit.
368  */
369 void fatalbox(char *fmt, ...)
370 {
371     char str[0x100];                   /* Make the size big enough */
372     va_list ap;
373     va_start(ap, fmt);
374     strcpy(str, "Fatal: ");
375     vsprintf(str + strlen(str), fmt, ap);
376     va_end(ap);
377     strcat(str, "\n");
378     tell_str(stderr, str);
379     errs++;
380
381     if (gui_mode) {
382         unsigned int msg_id = WM_RET_ERR_CNT;
383         if (list)
384             msg_id = WM_LS_RET_ERR_CNT;
385         while (!PostMessage
386                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
387                 0 /*lParam */ ))SleepEx(1000, TRUE);
388     }
389
390     exit(1);
391 }
392 void connection_fatal(char *fmt, ...)
393 {
394     char str[0x100];                   /* Make the size big enough */
395     va_list ap;
396     va_start(ap, fmt);
397     strcpy(str, "Fatal: ");
398     vsprintf(str + strlen(str), fmt, ap);
399     va_end(ap);
400     strcat(str, "\n");
401     tell_str(stderr, str);
402     errs++;
403
404     if (gui_mode) {
405         unsigned int msg_id = WM_RET_ERR_CNT;
406         if (list)
407             msg_id = WM_LS_RET_ERR_CNT;
408         while (!PostMessage
409                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
410                 0 /*lParam */ ))SleepEx(1000, TRUE);
411     }
412
413     exit(1);
414 }
415
416 /*
417  * Be told what socket we're supposed to be using.
418  */
419 static SOCKET scp_ssh_socket;
420 char *do_select(SOCKET skt, int startup)
421 {
422     if (startup)
423         scp_ssh_socket = skt;
424     else
425         scp_ssh_socket = INVALID_SOCKET;
426     return NULL;
427 }
428 extern int select_result(WPARAM, LPARAM);
429
430 /*
431  * Receive a block of data from the SSH link. Block until all data
432  * is available.
433  *
434  * To do this, we repeatedly call the SSH protocol module, with our
435  * own trap in from_backend() to catch the data that comes back. We
436  * do this until we have enough data.
437  */
438
439 static unsigned char *outptr;          /* where to put the data */
440 static unsigned outlen;                /* how much data required */
441 static unsigned char *pending = NULL;  /* any spare data */
442 static unsigned pendlen = 0, pendsize = 0;      /* length and phys. size of buffer */
443 int from_backend(int is_stderr, char *data, int datalen)
444 {
445     unsigned char *p = (unsigned char *) data;
446     unsigned len = (unsigned) datalen;
447
448     /*
449      * stderr data is just spouted to local stderr and otherwise
450      * ignored.
451      */
452     if (is_stderr) {
453         fwrite(data, 1, len, stderr);
454         return 0;
455     }
456
457     /*
458      * If this is before the real session begins, just return.
459      */
460     if (!outptr)
461         return 0;
462
463     if (outlen > 0) {
464         unsigned used = outlen;
465         if (used > len)
466             used = len;
467         memcpy(outptr, p, used);
468         outptr += used;
469         outlen -= used;
470         p += used;
471         len -= used;
472     }
473
474     if (len > 0) {
475         if (pendsize < pendlen + len) {
476             pendsize = pendlen + len + 4096;
477             pending = (pending ? srealloc(pending, pendsize) :
478                        smalloc(pendsize));
479             if (!pending)
480                 fatalbox("Out of memory");
481         }
482         memcpy(pending + pendlen, p, len);
483         pendlen += len;
484     }
485
486     return 0;
487 }
488 static int scp_process_network_event(void)
489 {
490     fd_set readfds;
491
492     FD_ZERO(&readfds);
493     FD_SET(scp_ssh_socket, &readfds);
494     if (select(1, &readfds, NULL, NULL, NULL) < 0)
495         return 0;                      /* doom */
496     select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
497     return 1;
498 }
499 static int ssh_scp_recv(unsigned char *buf, int len)
500 {
501     outptr = buf;
502     outlen = len;
503
504     /*
505      * See if the pending-input block contains some of what we
506      * need.
507      */
508     if (pendlen > 0) {
509         unsigned pendused = pendlen;
510         if (pendused > outlen)
511             pendused = outlen;
512         memcpy(outptr, pending, pendused);
513         memmove(pending, pending + pendused, pendlen - pendused);
514         outptr += pendused;
515         outlen -= pendused;
516         pendlen -= pendused;
517         if (pendlen == 0) {
518             pendsize = 0;
519             sfree(pending);
520             pending = NULL;
521         }
522         if (outlen == 0)
523             return len;
524     }
525
526     while (outlen > 0) {
527         if (!scp_process_network_event())
528             return 0;                  /* doom */
529     }
530
531     return len;
532 }
533
534 /*
535  * Loop through the ssh connection and authentication process.
536  */
537 static void ssh_scp_init(void)
538 {
539     if (scp_ssh_socket == INVALID_SOCKET)
540         return;
541     while (!back->sendok()) {
542         fd_set readfds;
543         FD_ZERO(&readfds);
544         FD_SET(scp_ssh_socket, &readfds);
545         if (select(1, &readfds, NULL, NULL, NULL) < 0)
546             return;                    /* doom */
547         select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
548     }
549     using_sftp = !ssh_fallback_cmd;
550 }
551
552 /*
553  *  Print an error message and exit after closing the SSH link.
554  */
555 static void bump(char *fmt, ...)
556 {
557     char str[0x100];                   /* Make the size big enough */
558     va_list ap;
559     va_start(ap, fmt);
560     strcpy(str, "Fatal: ");
561     vsprintf(str + strlen(str), fmt, ap);
562     va_end(ap);
563     strcat(str, "\n");
564     tell_str(stderr, str);
565     errs++;
566
567     if (back != NULL && back->socket() != NULL) {
568         char ch;
569         back->special(TS_EOF);
570         ssh_scp_recv(&ch, 1);
571     }
572
573     if (gui_mode) {
574         unsigned int msg_id = WM_RET_ERR_CNT;
575         if (list)
576             msg_id = WM_LS_RET_ERR_CNT;
577         while (!PostMessage
578                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
579                 0 /*lParam */ ))SleepEx(1000, TRUE);
580     }
581
582     exit(1);
583 }
584
585 static int get_line(const char *prompt, char *str, int maxlen, int is_pw)
586 {
587     HANDLE hin, hout;
588     DWORD savemode, newmode, i;
589
590     if (is_pw && password) {
591         static int tried_once = 0;
592
593         if (tried_once) {
594             return 0;
595         } else {
596             strncpy(str, password, maxlen);
597             str[maxlen - 1] = '\0';
598             tried_once = 1;
599             return 1;
600         }
601     }
602
603     /* GUI Adaptation - Sept 2000 */
604     if (gui_mode) {
605         if (maxlen > 0)
606             str[0] = '\0';
607     } else {
608         hin = GetStdHandle(STD_INPUT_HANDLE);
609         hout = GetStdHandle(STD_OUTPUT_HANDLE);
610         if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE)
611             bump("Cannot get standard input/output handles");
612
613         GetConsoleMode(hin, &savemode);
614         newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
615         if (is_pw)
616             newmode &= ~ENABLE_ECHO_INPUT;
617         else
618             newmode |= ENABLE_ECHO_INPUT;
619         SetConsoleMode(hin, newmode);
620
621         WriteFile(hout, prompt, strlen(prompt), &i, NULL);
622         ReadFile(hin, str, maxlen - 1, &i, NULL);
623
624         SetConsoleMode(hin, savemode);
625
626         if ((int) i > maxlen)
627             i = maxlen - 1;
628         else
629             i = i - 2;
630         str[i] = '\0';
631
632         if (is_pw)
633             WriteFile(hout, "\r\n", 2, &i, NULL);
634     }
635
636     return 1;
637 }
638
639 /*
640  *  Open an SSH connection to user@host and execute cmd.
641  */
642 static void do_cmd(char *host, char *user, char *cmd)
643 {
644     char *err, *realhost;
645     DWORD namelen;
646
647     if (host == NULL || host[0] == '\0')
648         bump("Empty host name");
649
650     /* Try to load settings for this host */
651     do_defaults(host, &cfg);
652     if (cfg.host[0] == '\0') {
653         /* No settings for this host; use defaults */
654         do_defaults(NULL, &cfg);
655         strncpy(cfg.host, host, sizeof(cfg.host) - 1);
656         cfg.host[sizeof(cfg.host) - 1] = '\0';
657         cfg.port = 22;
658     }
659
660     /*
661      * Trim leading whitespace off the hostname if it's there.
662      */
663     {
664         int space = strspn(cfg.host, " \t");
665         memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
666     }
667
668     /* See if host is of the form user@host */
669     if (cfg.host[0] != '\0') {
670         char *atsign = strchr(cfg.host, '@');
671         /* Make sure we're not overflowing the user field */
672         if (atsign) {
673             if (atsign - cfg.host < sizeof cfg.username) {
674                 strncpy(cfg.username, cfg.host, atsign - cfg.host);
675                 cfg.username[atsign - cfg.host] = '\0';
676             }
677             memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));
678         }
679     }
680
681     /*
682      * Trim a colon suffix off the hostname if it's there.
683      */
684     cfg.host[strcspn(cfg.host, ":")] = '\0';
685
686     /* Set username */
687     if (user != NULL && user[0] != '\0') {
688         strncpy(cfg.username, user, sizeof(cfg.username) - 1);
689         cfg.username[sizeof(cfg.username) - 1] = '\0';
690     } else if (cfg.username[0] == '\0') {
691         namelen = 0;
692         if (GetUserName(user, &namelen) == FALSE)
693             bump("Empty user name");
694         user = smalloc(namelen * sizeof(char));
695         GetUserName(user, &namelen);
696         if (verbose)
697             tell_user(stderr, "Guessing user name: %s", user);
698         strncpy(cfg.username, user, sizeof(cfg.username) - 1);
699         cfg.username[sizeof(cfg.username) - 1] = '\0';
700         free(user);
701     }
702
703     if (cfg.protocol != PROT_SSH)
704         cfg.port = 22;
705
706     if (portnumber)
707         cfg.port = portnumber;
708
709     /*
710      * Disable scary things which shouldn't be enabled for simple
711      * things like SCP and SFTP: agent forwarding, port forwarding,
712      * X forwarding.
713      */
714     cfg.x11_forward = 0;
715     cfg.agentfwd = 0;
716     cfg.portfwd[0] = cfg.portfwd[1] = '\0';
717
718     /*
719      * Attempt to start the SFTP subsystem as a first choice,
720      * falling back to the provided scp command if that fails.
721      */
722     strcpy(cfg.remote_cmd, "sftp");
723     cfg.ssh_subsys = TRUE;
724     cfg.remote_cmd_ptr2 = cmd;
725     cfg.ssh_subsys2 = FALSE;
726     cfg.nopty = TRUE;
727
728     back = &ssh_backend;
729
730     err = back->init(cfg.host, cfg.port, &realhost, 0);
731     if (err != NULL)
732         bump("ssh_init: %s", err);
733     ssh_scp_init();
734     if (verbose && realhost != NULL)
735         tell_user(stderr, "Connected to %s\n", realhost);
736     sfree(realhost);
737 }
738
739 /*
740  *  Update statistic information about current file.
741  */
742 static void print_stats(char *name, unsigned long size, unsigned long done,
743                         time_t start, time_t now)
744 {
745     float ratebs;
746     unsigned long eta;
747     char etastr[10];
748     int pct;
749     int len;
750     int elap;
751
752     elap = (unsigned long) difftime(now, start);
753
754     if (now > start)
755         ratebs = (float) done / elap;
756     else
757         ratebs = (float) done;
758
759     if (ratebs < 1.0)
760         eta = size - done;
761     else
762         eta = (unsigned long) ((size - done) / ratebs);
763     sprintf(etastr, "%02ld:%02ld:%02ld",
764             eta / 3600, (eta % 3600) / 60, eta % 60);
765
766     pct = (int) (100 * (done * 1.0 / size));
767
768     if (gui_mode)
769         /* GUI Adaptation - Sept 2000 */
770         gui_update_stats(name, size, pct, elap, done, eta, 
771                          (unsigned long) ratebs);
772     else {
773         len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
774                      name, done / 1024, ratebs / 1024.0, etastr, pct);
775         if (len < prev_stats_len)
776             printf("%*s", prev_stats_len - len, "");
777         prev_stats_len = len;
778
779         if (done == size)
780             printf("\n");
781     }
782 }
783
784 /*
785  *  Find a colon in str and return a pointer to the colon.
786  *  This is used to separate hostname from filename.
787  */
788 static char *colon(char *str)
789 {
790     /* We ignore a leading colon, since the hostname cannot be
791        empty. We also ignore a colon as second character because
792        of filenames like f:myfile.txt. */
793     if (str[0] == '\0' || str[0] == ':' || str[1] == ':')
794         return (NULL);
795     while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\')
796         str++;
797     if (*str == ':')
798         return (str);
799     else
800         return (NULL);
801 }
802
803 /*
804  * Return a pointer to the portion of str that comes after the last
805  * slash (or backslash or colon, if `local' is TRUE).
806  */
807 static char *stripslashes(char *str, int local)
808 {
809     char *p;
810
811     if (local) {
812         p = strchr(str, ':');
813         if (p) str = p+1;
814     }
815
816     p = strrchr(str, '/');
817     if (p) str = p+1;
818
819     if (local) {
820         p = strrchr(str, '\\');
821         if (p) str = p+1;
822     }
823
824     return str;
825 }
826
827 /*
828  * Determine whether a string is entirely composed of dots.
829  */
830 static int is_dots(char *str)
831 {
832     return str[strspn(str, ".")] == '\0';
833 }
834
835 /*
836  *  Wait for a response from the other side.
837  *  Return 0 if ok, -1 if error.
838  */
839 static int response(void)
840 {
841     char ch, resp, rbuf[2048];
842     int p;
843
844     if (ssh_scp_recv(&resp, 1) <= 0)
845         bump("Lost connection");
846
847     p = 0;
848     switch (resp) {
849       case 0:                          /* ok */
850         return (0);
851       default:
852         rbuf[p++] = resp;
853         /* fallthrough */
854       case 1:                          /* error */
855       case 2:                          /* fatal error */
856         do {
857             if (ssh_scp_recv(&ch, 1) <= 0)
858                 bump("Protocol error: Lost connection");
859             rbuf[p++] = ch;
860         } while (p < sizeof(rbuf) && ch != '\n');
861         rbuf[p - 1] = '\0';
862         if (resp == 1)
863             tell_user(stderr, "%s\n", rbuf);
864         else
865             bump("%s", rbuf);
866         errs++;
867         return (-1);
868     }
869 }
870
871 int sftp_recvdata(char *buf, int len)
872 {
873     return ssh_scp_recv(buf, len);
874 }
875 int sftp_senddata(char *buf, int len)
876 {
877     back->send((unsigned char *) buf, len);
878     return 1;
879 }
880
881 /* ----------------------------------------------------------------------
882  * sftp-based replacement for the hacky `pscp -ls'.
883  */
884 static int sftp_ls_compare(const void *av, const void *bv)
885 {
886     const struct fxp_name *a = (const struct fxp_name *) av;
887     const struct fxp_name *b = (const struct fxp_name *) bv;
888     return strcmp(a->filename, b->filename);
889 }
890 void scp_sftp_listdir(char *dirname)
891 {
892     struct fxp_handle *dirh;
893     struct fxp_names *names;
894     struct fxp_name *ournames;
895     int nnames, namesize;
896     int i;
897
898     printf("Listing directory %s\n", dirname);
899
900     dirh = fxp_opendir(dirname);
901     if (dirh == NULL) {
902         printf("Unable to open %s: %s\n", dirname, fxp_error());
903     } else {
904         nnames = namesize = 0;
905         ournames = NULL;
906
907         while (1) {
908
909             names = fxp_readdir(dirh);
910             if (names == NULL) {
911                 if (fxp_error_type() == SSH_FX_EOF)
912                     break;
913                 printf("Reading directory %s: %s\n", dirname, fxp_error());
914                 break;
915             }
916             if (names->nnames == 0) {
917                 fxp_free_names(names);
918                 break;
919             }
920
921             if (nnames + names->nnames >= namesize) {
922                 namesize += names->nnames + 128;
923                 ournames =
924                     srealloc(ournames, namesize * sizeof(*ournames));
925             }
926
927             for (i = 0; i < names->nnames; i++)
928                 ournames[nnames++] = names->names[i];
929
930             names->nnames = 0;         /* prevent free_names */
931             fxp_free_names(names);
932         }
933         fxp_close(dirh);
934
935         /*
936          * Now we have our filenames. Sort them by actual file
937          * name, and then output the longname parts.
938          */
939         qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);
940
941         /*
942          * And print them.
943          */
944         for (i = 0; i < nnames; i++)
945             printf("%s\n", ournames[i].longname);
946     }
947 }
948
949 /* ----------------------------------------------------------------------
950  * Helper routines that contain the actual SCP protocol elements,
951  * implemented both as SCP1 and SFTP.
952  */
953
954 static struct scp_sftp_dirstack {
955     struct scp_sftp_dirstack *next;
956     struct fxp_name *names;
957     int namepos, namelen;
958     char *dirpath;
959     char *wildcard;
960     int matched_something;             /* wildcard match set was non-empty */
961 } *scp_sftp_dirstack_head;
962 static char *scp_sftp_remotepath, *scp_sftp_currentname;
963 static char *scp_sftp_wildcard;
964 static int scp_sftp_targetisdir, scp_sftp_donethistarget;
965 static int scp_sftp_preserve, scp_sftp_recursive;
966 static unsigned long scp_sftp_mtime, scp_sftp_atime;
967 static int scp_has_times;
968 static struct fxp_handle *scp_sftp_filehandle;
969 static uint64 scp_sftp_fileoffset;
970
971 void scp_source_setup(char *target, int shouldbedir)
972 {
973     if (using_sftp) {
974         /*
975          * Find out whether the target filespec is in fact a
976          * directory.
977          */
978         struct fxp_attrs attrs;
979
980         if (!fxp_stat(target, &attrs) ||
981             !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS))
982             scp_sftp_targetisdir = 0;
983         else
984             scp_sftp_targetisdir = (attrs.permissions & 0040000) != 0;
985
986         if (shouldbedir && !scp_sftp_targetisdir) {
987             bump("pscp: remote filespec %s: not a directory\n", target);
988         }
989
990         scp_sftp_remotepath = dupstr(target);
991
992         scp_has_times = 0;
993     } else {
994         (void) response();
995     }
996 }
997
998 int scp_send_errmsg(char *str)
999 {
1000     if (using_sftp) {
1001         /* do nothing; we never need to send our errors to the server */
1002     } else {
1003         back->send("\001", 1);         /* scp protocol error prefix */
1004         back->send(str, strlen(str));
1005     }
1006     return 0;                          /* can't fail */
1007 }
1008
1009 int scp_send_filetimes(unsigned long mtime, unsigned long atime)
1010 {
1011     if (using_sftp) {
1012         scp_sftp_mtime = mtime;
1013         scp_sftp_atime = atime;
1014         scp_has_times = 1;
1015         return 0;
1016     } else {
1017         char buf[80];
1018         sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
1019         back->send(buf, strlen(buf));
1020         return response();
1021     }
1022 }
1023
1024 int scp_send_filename(char *name, unsigned long size, int modes)
1025 {
1026     if (using_sftp) {
1027         char *fullname;
1028         if (scp_sftp_targetisdir) {
1029             fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
1030         } else {
1031             fullname = dupstr(scp_sftp_remotepath);
1032         }
1033         scp_sftp_filehandle =
1034             fxp_open(fullname, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
1035         if (!scp_sftp_filehandle) {
1036             tell_user(stderr, "pscp: unable to open %s: %s",
1037                       fullname, fxp_error());
1038             errs++;
1039             return 1;
1040         }
1041         scp_sftp_fileoffset = uint64_make(0, 0);
1042         sfree(fullname);
1043         return 0;
1044     } else {
1045         char buf[40];
1046         sprintf(buf, "C%04o %lu ", modes, size);
1047         back->send(buf, strlen(buf));
1048         back->send(name, strlen(name));
1049         back->send("\n", 1);
1050         return response();
1051     }
1052 }
1053
1054 int scp_send_filedata(char *data, int len)
1055 {
1056     if (using_sftp) {
1057         if (!scp_sftp_filehandle) {
1058             return 1;
1059         }
1060         if (!fxp_write(scp_sftp_filehandle, data, scp_sftp_fileoffset, len)) {
1061             tell_user(stderr, "error while writing: %s\n", fxp_error());
1062             errs++;
1063             return 1;
1064         }
1065         scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len);
1066         return 0;
1067     } else {
1068         int bufsize = back->send(data, len);
1069
1070         /*
1071          * If the network transfer is backing up - that is, the
1072          * remote site is not accepting data as fast as we can
1073          * produce it - then we must loop on network events until
1074          * we have space in the buffer again.
1075          */
1076         while (bufsize > MAX_SCP_BUFSIZE) {
1077             if (!scp_process_network_event())
1078                 return 1;
1079             bufsize = back->sendbuffer();
1080         }
1081
1082         return 0;
1083     }
1084 }
1085
1086 int scp_send_finish(void)
1087 {
1088     if (using_sftp) {
1089         struct fxp_attrs attrs;
1090         if (!scp_sftp_filehandle) {
1091             return 1;
1092         }
1093         if (scp_has_times) {
1094             attrs.flags = SSH_FILEXFER_ATTR_ACMODTIME;
1095             attrs.atime = scp_sftp_atime;
1096             attrs.mtime = scp_sftp_mtime;
1097             if (!fxp_fsetstat(scp_sftp_filehandle, attrs)) {
1098                 tell_user(stderr, "unable to set file times: %s\n", fxp_error());
1099                 errs++;
1100             }
1101         }
1102         fxp_close(scp_sftp_filehandle);
1103         scp_has_times = 0;
1104         return 0;
1105     } else {
1106         back->send("", 1);
1107         return response();
1108     }
1109 }
1110
1111 char *scp_save_remotepath(void)
1112 {
1113     if (using_sftp)
1114         return scp_sftp_remotepath;
1115     else
1116         return NULL;
1117 }
1118
1119 void scp_restore_remotepath(char *data)
1120 {
1121     if (using_sftp)
1122         scp_sftp_remotepath = data;
1123 }
1124
1125 int scp_send_dirname(char *name, int modes)
1126 {
1127     if (using_sftp) {
1128         char *fullname;
1129         char const *err;
1130         struct fxp_attrs attrs;
1131         if (scp_sftp_targetisdir) {
1132             fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
1133         } else {
1134             fullname = dupstr(scp_sftp_remotepath);
1135         }
1136
1137         /*
1138          * We don't worry about whether we managed to create the
1139          * directory, because if it exists already it's OK just to
1140          * use it. Instead, we will stat it afterwards, and if it
1141          * exists and is a directory we will assume we were either
1142          * successful or it didn't matter.
1143          */
1144         if (!fxp_mkdir(fullname))
1145             err = fxp_error();
1146         else
1147             err = "server reported no error";
1148         if (!fxp_stat(fullname, &attrs) ||
1149             !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) ||
1150             !(attrs.permissions & 0040000)) {
1151             tell_user(stderr, "unable to create directory %s: %s",
1152                       fullname, err);
1153             errs++;
1154             return 1;
1155         }
1156
1157         scp_sftp_remotepath = fullname;
1158
1159         return 0;
1160     } else {
1161         char buf[40];
1162         sprintf(buf, "D%04o 0 ", modes);
1163         back->send(buf, strlen(buf));
1164         back->send(name, strlen(name));
1165         back->send("\n", 1);
1166         return response();
1167     }
1168 }
1169
1170 int scp_send_enddir(void)
1171 {
1172     if (using_sftp) {
1173         sfree(scp_sftp_remotepath);
1174         return 0;
1175     } else {
1176         back->send("E\n", 2);
1177         return response();
1178     }
1179 }
1180
1181 /*
1182  * Yes, I know; I have an scp_sink_setup _and_ an scp_sink_init.
1183  * That's bad. The difference is that scp_sink_setup is called once
1184  * right at the start, whereas scp_sink_init is called to
1185  * initialise every level of recursion in the protocol.
1186  */
1187 int scp_sink_setup(char *source, int preserve, int recursive)
1188 {
1189     if (using_sftp) {
1190         char *newsource;
1191         /*
1192          * It's possible that the source string we've been given
1193          * contains a wildcard. If so, we must split the directory
1194          * away from the wildcard itself (throwing an error if any
1195          * wildcardness comes before the final slash) and arrange
1196          * things so that a dirstack entry will be set up.
1197          */
1198         newsource = smalloc(1+strlen(source));
1199         if (!wc_unescape(newsource, source)) {
1200             /* Yes, here we go; it's a wildcard. Bah. */
1201             char *dupsource, *lastpart, *dirpart, *wildcard;
1202             dupsource = dupstr(source);
1203             lastpart = stripslashes(dupsource, 0);
1204             wildcard = dupstr(lastpart);
1205             *lastpart = '\0';
1206             if (*dupsource && dupsource[1]) {
1207                 /*
1208                  * The remains of dupsource are at least two
1209                  * characters long, meaning the pathname wasn't
1210                  * empty or just `/'. Hence, we remove the trailing
1211                  * slash.
1212                  */
1213                 lastpart[-1] = '\0';
1214             } else if (!*dupsource) {
1215                 /*
1216                  * The remains of dupsource are _empty_ - the whole
1217                  * pathname was a wildcard. Hence we need to
1218                  * replace it with ".".
1219                  */
1220                 sfree(dupsource);
1221                 dupsource = dupstr(".");
1222             }
1223
1224             /*
1225              * Now we have separated our string into dupsource (the
1226              * directory part) and wildcard. Both of these will
1227              * need freeing at some point. Next step is to remove
1228              * wildcard escapes from the directory part, throwing
1229              * an error if it contains a real wildcard.
1230              */
1231             dirpart = smalloc(1+strlen(dupsource));
1232             if (!wc_unescape(dirpart, dupsource)) {
1233                 tell_user(stderr, "%s: multiple-level wildcards unsupported",
1234                           source);
1235                 errs++;
1236                 sfree(dirpart);
1237                 sfree(wildcard);
1238                 sfree(dupsource);
1239                 return 1;
1240             }
1241
1242             /*
1243              * Now we have dirpart (unescaped, ie a valid remote
1244              * path), and wildcard (a wildcard). This will be
1245              * sufficient to arrange a dirstack entry.
1246              */
1247             scp_sftp_remotepath = dirpart;
1248             scp_sftp_wildcard = wildcard;
1249             sfree(dupsource);
1250         } else {
1251             scp_sftp_remotepath = newsource;
1252             scp_sftp_wildcard = NULL;
1253         }
1254         scp_sftp_preserve = preserve;
1255         scp_sftp_recursive = recursive;
1256         scp_sftp_donethistarget = 0;
1257         scp_sftp_dirstack_head = NULL;
1258     }
1259     return 0;
1260 }
1261
1262 int scp_sink_init(void)
1263 {
1264     if (!using_sftp) {
1265         back->send("", 1);
1266     }
1267     return 0;
1268 }
1269
1270 #define SCP_SINK_FILE   1
1271 #define SCP_SINK_DIR    2
1272 #define SCP_SINK_ENDDIR 3
1273 #define SCP_SINK_RETRY  4              /* not an action; just try again */
1274 struct scp_sink_action {
1275     int action;                        /* FILE, DIR, ENDDIR */
1276     char *buf;                         /* will need freeing after use */
1277     char *name;                        /* filename or dirname (not ENDDIR) */
1278     int mode;                          /* access mode (not ENDDIR) */
1279     unsigned long size;                /* file size (not ENDDIR) */
1280     int settime;                       /* 1 if atime and mtime are filled */
1281     unsigned long atime, mtime;        /* access times for the file */
1282 };
1283
1284 int scp_get_sink_action(struct scp_sink_action *act)
1285 {
1286     if (using_sftp) {
1287         char *fname;
1288         int must_free_fname;
1289         struct fxp_attrs attrs;
1290         int ret;
1291
1292         if (!scp_sftp_dirstack_head) {
1293             if (!scp_sftp_donethistarget) {
1294                 /*
1295                  * Simple case: we are only dealing with one file.
1296                  */
1297                 fname = scp_sftp_remotepath;
1298                 must_free_fname = 0;
1299                 scp_sftp_donethistarget = 1;
1300             } else {
1301                 /*
1302                  * Even simpler case: one file _which we've done_.
1303                  * Return 1 (finished).
1304                  */
1305                 return 1;
1306             }
1307         } else {
1308             /*
1309              * We're now in the middle of stepping through a list
1310              * of names returned from fxp_readdir(); so let's carry
1311              * on.
1312              */
1313             struct scp_sftp_dirstack *head = scp_sftp_dirstack_head;
1314             while (head->namepos < head->namelen &&
1315                    (is_dots(head->names[head->namepos].filename) ||
1316                     (head->wildcard &&
1317                      !wc_match(head->wildcard,
1318                                head->names[head->namepos].filename))))
1319                 head->namepos++;       /* skip . and .. */
1320             if (head->namepos < head->namelen) {
1321                 head->matched_something = 1;
1322                 fname = dupcat(head->dirpath, "/",
1323                                head->names[head->namepos++].filename,
1324                                NULL);
1325                 must_free_fname = 1;
1326             } else {
1327                 /*
1328                  * We've come to the end of the list; pop it off
1329                  * the stack and return an ENDDIR action (or RETRY
1330                  * if this was a wildcard match).
1331                  */
1332                 if (head->wildcard) {
1333                     act->action = SCP_SINK_RETRY;
1334                     if (!head->matched_something) {
1335                         tell_user(stderr, "pscp: wildcard '%s' matched "
1336                                   "no files", head->wildcard);
1337                         errs++;
1338                     }
1339                     sfree(head->wildcard);
1340
1341                 } else {
1342                     act->action = SCP_SINK_ENDDIR;
1343                 }
1344
1345                 sfree(head->dirpath);
1346                 sfree(head->names);
1347                 scp_sftp_dirstack_head = head->next;
1348                 sfree(head);
1349
1350                 return 0;
1351             }
1352         }
1353
1354         /*
1355          * Now we have a filename. Stat it, and see if it's a file
1356          * or a directory.
1357          */
1358         ret = fxp_stat(fname, &attrs);
1359         if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) {
1360             tell_user(stderr, "unable to identify %s: %s", fname,
1361                       ret ? "file type not supplied" : fxp_error());
1362             errs++;
1363             return 1;
1364         }
1365
1366         if (attrs.permissions & 0040000) {
1367             struct scp_sftp_dirstack *newitem;
1368             struct fxp_handle *dirhandle;
1369             int nnames, namesize;
1370             struct fxp_name *ournames;
1371             struct fxp_names *names;
1372
1373             /*
1374              * It's a directory. If we're not in recursive mode,
1375              * this merits a complaint (which is fatal if the name
1376              * was specified directly, but not if it was matched by
1377              * a wildcard).
1378              * 
1379              * We skip this complaint completely if
1380              * scp_sftp_wildcard is set, because that's an
1381              * indication that we're not actually supposed to
1382              * _recursively_ transfer the dir, just scan it for
1383              * things matching the wildcard.
1384              */
1385             if (!scp_sftp_recursive && !scp_sftp_wildcard) {
1386                 tell_user(stderr, "pscp: %s: is a directory", fname);
1387                 errs++;
1388                 if (must_free_fname) sfree(fname);
1389                 if (scp_sftp_dirstack_head) {
1390                     act->action = SCP_SINK_RETRY;
1391                     return 0;
1392                 } else {
1393                     return 1;
1394                 }
1395             }
1396
1397             /*
1398              * Otherwise, the fun begins. We must fxp_opendir() the
1399              * directory, slurp the filenames into memory, return
1400              * SCP_SINK_DIR (unless this is a wildcard match), and
1401              * set targetisdir. The next time we're called, we will
1402              * run through the list of filenames one by one,
1403              * matching them against a wildcard if present.
1404              * 
1405              * If targetisdir is _already_ set (meaning we're
1406              * already in the middle of going through another such
1407              * list), we must push the other (target,namelist) pair
1408              * on a stack.
1409              */
1410             dirhandle = fxp_opendir(fname);
1411             if (!dirhandle) {
1412                 tell_user(stderr, "scp: unable to open directory %s: %s",
1413                           fname, fxp_error());
1414                 if (must_free_fname) sfree(fname);
1415                 errs++;
1416                 return 1;
1417             }
1418             nnames = namesize = 0;
1419             ournames = NULL;
1420             while (1) {
1421                 int i;
1422
1423                 names = fxp_readdir(dirhandle);
1424                 if (names == NULL) {
1425                     if (fxp_error_type() == SSH_FX_EOF)
1426                         break;
1427                     tell_user(stderr, "scp: reading directory %s: %s\n",
1428                               fname, fxp_error());
1429                     if (must_free_fname) sfree(fname);
1430                     sfree(ournames);
1431                     errs++;
1432                     return 1;
1433                 }
1434                 if (names->nnames == 0) {
1435                     fxp_free_names(names);
1436                     break;
1437                 }
1438                 if (nnames + names->nnames >= namesize) {
1439                     namesize += names->nnames + 128;
1440                     ournames =
1441                         srealloc(ournames, namesize * sizeof(*ournames));
1442                 }
1443                 for (i = 0; i < names->nnames; i++)
1444                     ournames[nnames++] = names->names[i];
1445                 names->nnames = 0;             /* prevent free_names */
1446                 fxp_free_names(names);
1447             }
1448             fxp_close(dirhandle);
1449
1450             newitem = smalloc(sizeof(struct scp_sftp_dirstack));
1451             newitem->next = scp_sftp_dirstack_head;
1452             newitem->names = ournames;
1453             newitem->namepos = 0;
1454             newitem->namelen = nnames;
1455             if (must_free_fname)
1456                 newitem->dirpath = fname;
1457             else
1458                 newitem->dirpath = dupstr(fname);
1459             if (scp_sftp_wildcard) {
1460                 newitem->wildcard = scp_sftp_wildcard;
1461                 newitem->matched_something = 0;
1462                 scp_sftp_wildcard = NULL;
1463             } else {
1464                 newitem->wildcard = NULL;
1465             }
1466             scp_sftp_dirstack_head = newitem;
1467
1468             if (newitem->wildcard) {
1469                 act->action = SCP_SINK_RETRY;
1470             } else {
1471                 act->action = SCP_SINK_DIR;
1472                 act->buf = dupstr(stripslashes(fname, 0));
1473                 act->name = act->buf;
1474                 act->size = 0;         /* duhh, it's a directory */
1475                 act->mode = 07777 & attrs.permissions;
1476                 if (scp_sftp_preserve &&
1477                     (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
1478                     act->atime = attrs.atime;
1479                     act->mtime = attrs.mtime;
1480                     act->settime = 1;
1481                 } else
1482                     act->settime = 0;
1483             }
1484             return 0;
1485
1486         } else {
1487             /*
1488              * It's a file. Return SCP_SINK_FILE.
1489              */
1490             act->action = SCP_SINK_FILE;
1491             act->buf = dupstr(stripslashes(fname, 0));
1492             act->name = act->buf;
1493             if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
1494                 if (uint64_compare(attrs.size,
1495                                    uint64_make(0, ULONG_MAX)) > 0) {
1496                     act->size = ULONG_MAX;   /* *boggle* */
1497                 } else
1498                     act->size = attrs.size.lo;
1499             } else
1500                 act->size = ULONG_MAX;   /* no idea */
1501             act->mode = 07777 & attrs.permissions;
1502             if (scp_sftp_preserve &&
1503                 (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
1504                 act->atime = attrs.atime;
1505                 act->mtime = attrs.mtime;
1506                 act->settime = 1;
1507             } else
1508                 act->settime = 0;
1509             if (must_free_fname)
1510                 scp_sftp_currentname = fname;
1511             else
1512                 scp_sftp_currentname = dupstr(fname);
1513             return 0;
1514         }
1515
1516     } else {
1517         int done = 0;
1518         int i, bufsize;
1519         int action;
1520         char ch;
1521
1522         act->settime = 0;
1523         act->buf = NULL;
1524         bufsize = 0;
1525
1526         while (!done) {
1527             if (ssh_scp_recv(&ch, 1) <= 0)
1528                 return 1;
1529             if (ch == '\n')
1530                 bump("Protocol error: Unexpected newline");
1531             i = 0;
1532             action = ch;
1533             do {
1534                 if (ssh_scp_recv(&ch, 1) <= 0)
1535                     bump("Lost connection");
1536                 if (i >= bufsize) {
1537                     bufsize = i + 128;
1538                     act->buf = srealloc(act->buf, bufsize);
1539                 }
1540                 act->buf[i++] = ch;
1541             } while (ch != '\n');
1542             act->buf[i - 1] = '\0';
1543             switch (action) {
1544               case '\01':                      /* error */
1545                 tell_user(stderr, "%s\n", act->buf);
1546                 errs++;
1547                 continue;                      /* go round again */
1548               case '\02':                      /* fatal error */
1549                 bump("%s", act->buf);
1550               case 'E':
1551                 back->send("", 1);
1552                 act->action = SCP_SINK_ENDDIR;
1553                 return 0;
1554               case 'T':
1555                 if (sscanf(act->buf, "%ld %*d %ld %*d",
1556                            &act->mtime, &act->atime) == 2) {
1557                     act->settime = 1;
1558                     back->send("", 1);
1559                     continue;          /* go round again */
1560                 }
1561                 bump("Protocol error: Illegal time format");
1562               case 'C':
1563               case 'D':
1564                 act->action = (action == 'C' ? SCP_SINK_FILE : SCP_SINK_DIR);
1565                 break;
1566               default:
1567                 bump("Protocol error: Expected control record");
1568             }
1569             /*
1570              * We will go round this loop only once, unless we hit
1571              * `continue' above.
1572              */
1573             done = 1;
1574         }
1575
1576         /*
1577          * If we get here, we must have seen SCP_SINK_FILE or
1578          * SCP_SINK_DIR.
1579          */
1580         if (sscanf(act->buf, "%o %lu %n", &act->mode, &act->size, &i) != 2)
1581             bump("Protocol error: Illegal file descriptor format");
1582         act->name = act->buf + i;
1583         return 0;
1584     }
1585 }
1586
1587 int scp_accept_filexfer(void)
1588 {
1589     if (using_sftp) {
1590         scp_sftp_filehandle =
1591             fxp_open(scp_sftp_currentname, SSH_FXF_READ);
1592         if (!scp_sftp_filehandle) {
1593             tell_user(stderr, "pscp: unable to open %s: %s",
1594                       scp_sftp_currentname, fxp_error());
1595             errs++;
1596             return 1;
1597         }
1598         scp_sftp_fileoffset = uint64_make(0, 0);
1599         sfree(scp_sftp_currentname);
1600         return 0;
1601     } else {
1602         back->send("", 1);
1603         return 0;                      /* can't fail */
1604     }
1605 }
1606
1607 int scp_recv_filedata(char *data, int len)
1608 {
1609     if (using_sftp) {
1610         int actuallen = fxp_read(scp_sftp_filehandle, data,
1611                                  scp_sftp_fileoffset, len);
1612         if (actuallen == -1 && fxp_error_type() != SSH_FX_EOF) {
1613             tell_user(stderr, "pscp: error while reading: %s", fxp_error());
1614             errs++;
1615             return -1;
1616         }
1617         if (actuallen < 0)
1618             actuallen = 0;
1619
1620         scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, actuallen);
1621
1622         return actuallen;
1623     } else {
1624         return ssh_scp_recv(data, len);
1625     }
1626 }
1627
1628 int scp_finish_filerecv(void)
1629 {
1630     if (using_sftp) {
1631         fxp_close(scp_sftp_filehandle);
1632         return 0;
1633     } else {
1634         back->send("", 1);
1635         return response();
1636     }
1637 }
1638
1639 /* ----------------------------------------------------------------------
1640  *  Send an error message to the other side and to the screen.
1641  *  Increment error counter.
1642  */
1643 static void run_err(const char *fmt, ...)
1644 {
1645     char str[2048];
1646     va_list ap;
1647     va_start(ap, fmt);
1648     errs++;
1649     strcpy(str, "scp: ");
1650     vsprintf(str + strlen(str), fmt, ap);
1651     strcat(str, "\n");
1652     scp_send_errmsg(str);
1653     tell_user(stderr, "%s", str);
1654     va_end(ap);
1655 }
1656
1657 /*
1658  *  Execute the source part of the SCP protocol.
1659  */
1660 static void source(char *src)
1661 {
1662     unsigned long size;
1663     char *last;
1664     HANDLE f;
1665     DWORD attr;
1666     unsigned long i;
1667     unsigned long stat_bytes;
1668     time_t stat_starttime, stat_lasttime;
1669
1670     attr = GetFileAttributes(src);
1671     if (attr == (DWORD) - 1) {
1672         run_err("%s: No such file or directory", src);
1673         return;
1674     }
1675
1676     if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1677         if (recursive) {
1678             /*
1679              * Avoid . and .. directories.
1680              */
1681             char *p;
1682             p = strrchr(src, '/');
1683             if (!p)
1684                 p = strrchr(src, '\\');
1685             if (!p)
1686                 p = src;
1687             else
1688                 p++;
1689             if (!strcmp(p, ".") || !strcmp(p, ".."))
1690                 /* skip . and .. */ ;
1691             else
1692                 rsource(src);
1693         } else {
1694             run_err("%s: not a regular file", src);
1695         }
1696         return;
1697     }
1698
1699     if ((last = strrchr(src, '/')) == NULL)
1700         last = src;
1701     else
1702         last++;
1703     if (strrchr(last, '\\') != NULL)
1704         last = strrchr(last, '\\') + 1;
1705     if (last == src && strchr(src, ':') != NULL)
1706         last = strchr(src, ':') + 1;
1707
1708     f = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL,
1709                    OPEN_EXISTING, 0, 0);
1710     if (f == INVALID_HANDLE_VALUE) {
1711         run_err("%s: Cannot open file", src);
1712         return;
1713     }
1714
1715     if (preserve) {
1716         FILETIME actime, wrtime;
1717         unsigned long mtime, atime;
1718         GetFileTime(f, NULL, &actime, &wrtime);
1719         TIME_WIN_TO_POSIX(actime, atime);
1720         TIME_WIN_TO_POSIX(wrtime, mtime);
1721         if (scp_send_filetimes(mtime, atime))
1722             return;
1723     }
1724
1725     size = GetFileSize(f, NULL);
1726     if (verbose)
1727         tell_user(stderr, "Sending file %s, size=%lu", last, size);
1728     if (scp_send_filename(last, size, 0644))
1729         return;
1730
1731     stat_bytes = 0;
1732     stat_starttime = time(NULL);
1733     stat_lasttime = 0;
1734
1735     for (i = 0; i < size; i += 4096) {
1736         char transbuf[4096];
1737         DWORD j, k = 4096;
1738
1739         if (i + k > size)
1740             k = size - i;
1741         if (!ReadFile(f, transbuf, k, &j, NULL) || j != k) {
1742             if (statistics)
1743                 printf("\n");
1744             bump("%s: Read error", src);
1745         }
1746         if (scp_send_filedata(transbuf, k))
1747             bump("%s: Network error occurred", src);
1748
1749         if (statistics) {
1750             stat_bytes += k;
1751             if (time(NULL) != stat_lasttime || i + k == size) {
1752                 stat_lasttime = time(NULL);
1753                 print_stats(last, size, stat_bytes,
1754                             stat_starttime, stat_lasttime);
1755             }
1756         }
1757
1758     }
1759     CloseHandle(f);
1760
1761     (void) scp_send_finish();
1762 }
1763
1764 /*
1765  *  Recursively send the contents of a directory.
1766  */
1767 static void rsource(char *src)
1768 {
1769     char *last, *findfile;
1770     char *save_target;
1771     HANDLE dir;
1772     WIN32_FIND_DATA fdat;
1773     int ok;
1774
1775     if ((last = strrchr(src, '/')) == NULL)
1776         last = src;
1777     else
1778         last++;
1779     if (strrchr(last, '\\') != NULL)
1780         last = strrchr(last, '\\') + 1;
1781     if (last == src && strchr(src, ':') != NULL)
1782         last = strchr(src, ':') + 1;
1783
1784     /* maybe send filetime */
1785
1786     save_target = scp_save_remotepath();
1787
1788     if (verbose)
1789         tell_user(stderr, "Entering directory: %s", last);
1790     if (scp_send_dirname(last, 0755))
1791         return;
1792
1793     findfile = dupcat(src, "/*", NULL);
1794     dir = FindFirstFile(findfile, &fdat);
1795     ok = (dir != INVALID_HANDLE_VALUE);
1796     while (ok) {
1797         if (strcmp(fdat.cFileName, ".") == 0 ||
1798             strcmp(fdat.cFileName, "..") == 0) {
1799             /* ignore . and .. */
1800         } else {
1801             char *foundfile = dupcat(src, "/", fdat.cFileName, NULL);
1802             source(foundfile);
1803             sfree(foundfile);
1804         }
1805         ok = FindNextFile(dir, &fdat);
1806     }
1807     FindClose(dir);
1808     sfree(findfile);
1809
1810     (void) scp_send_enddir();
1811
1812     scp_restore_remotepath(save_target);
1813 }
1814
1815 /*
1816  * Execute the sink part of the SCP protocol.
1817  */
1818 static void sink(char *targ, char *src)
1819 {
1820     char *destfname;
1821     int targisdir = 0;
1822     int exists;
1823     DWORD attr;
1824     HANDLE f;
1825     unsigned long received;
1826     int wrerror = 0;
1827     unsigned long stat_bytes;
1828     time_t stat_starttime, stat_lasttime;
1829     char *stat_name;
1830
1831     attr = GetFileAttributes(targ);
1832     if (attr != (DWORD) - 1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
1833         targisdir = 1;
1834
1835     if (targetshouldbedirectory && !targisdir)
1836         bump("%s: Not a directory", targ);
1837
1838     scp_sink_init();
1839     while (1) {
1840         struct scp_sink_action act;
1841         if (scp_get_sink_action(&act))
1842             return;
1843
1844         if (act.action == SCP_SINK_ENDDIR)
1845             return;
1846
1847         if (act.action == SCP_SINK_RETRY)
1848             continue;
1849
1850         if (targisdir) {
1851             /*
1852              * Prevent the remote side from maliciously writing to
1853              * files outside the target area by sending a filename
1854              * containing `../'. In fact, it shouldn't be sending
1855              * filenames with any slashes or colons in at all; so
1856              * we'll find the last slash, backslash or colon in the
1857              * filename and use only the part after that. (And
1858              * warn!)
1859              * 
1860              * In addition, we also ensure here that if we're
1861              * copying a single file and the target is a directory
1862              * (common usage: `pscp host:filename .') the remote
1863              * can't send us a _different_ file name. We can
1864              * distinguish this case because `src' will be non-NULL
1865              * and the last component of that will fail to match
1866              * (the last component of) the name sent.
1867              * 
1868              * Well, not always; if `src' is a wildcard, we do
1869              * expect to get back filenames that don't correspond
1870              * exactly to it. Ideally in this case, we would like
1871              * to ensure that the returned filename actually
1872              * matches the wildcard pattern - but one of SCP's
1873              * protocol infelicities is that wildcard matching is
1874              * done at the server end _by the server's rules_ and
1875              * so in general this is infeasible. Hence, we only
1876              * accept filenames that don't correspond to `src' if
1877              * unsafe mode is enabled or we are using SFTP (which
1878              * resolves remote wildcards on the client side and can
1879              * be trusted).
1880              */
1881             char *striptarget, *stripsrc;
1882
1883             striptarget = stripslashes(act.name, 1);
1884             if (striptarget != act.name) {
1885                 tell_user(stderr, "warning: remote host sent a compound"
1886                           " pathname '%s'", act.name);
1887                 tell_user(stderr, "         renaming local file to '%s'",
1888                           striptarget);
1889             }
1890
1891             /*
1892              * Also check to see if the target filename is '.' or
1893              * '..', or indeed '...' and so on because Windows
1894              * appears to interpret those like '..'.
1895              */
1896             if (is_dots(striptarget)) {
1897                 bump("security violation: remote host attempted to write to"
1898                      " a '.' or '..' path!");
1899             }
1900
1901             if (src) {
1902                 stripsrc = stripslashes(src, 1);
1903                 if (strcmp(striptarget, stripsrc) &&
1904                     !using_sftp && !scp_unsafe_mode) {
1905                     tell_user(stderr, "warning: remote host tried to write "
1906                               "to a file called '%s'", striptarget);
1907                     tell_user(stderr, "         when we requested a file "
1908                               "called '%s'.", stripsrc);
1909                     tell_user(stderr, "         If this is a wildcard, "
1910                               "consider upgrading to SSH 2 or using");
1911                     tell_user(stderr, "         the '-unsafe' option. Renaming"
1912                               " of this file has been disallowed.");
1913                     /* Override the name the server provided with our own. */
1914                     striptarget = stripsrc;
1915                 }
1916             }
1917
1918             if (targ[0] != '\0')
1919                 destfname = dupcat(targ, "\\", striptarget, NULL);
1920             else
1921                 destfname = dupstr(striptarget);
1922         } else {
1923             /*
1924              * In this branch of the if, the target area is a
1925              * single file with an explicitly specified name in any
1926              * case, so there's no danger.
1927              */
1928             destfname = dupstr(targ);
1929         }
1930         attr = GetFileAttributes(destfname);
1931         exists = (attr != (DWORD) - 1);
1932
1933         if (act.action == SCP_SINK_DIR) {
1934             if (exists && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
1935                 run_err("%s: Not a directory", destfname);
1936                 continue;
1937             }
1938             if (!exists) {
1939                 if (!CreateDirectory(destfname, NULL)) {
1940                     run_err("%s: Cannot create directory", destfname);
1941                     continue;
1942                 }
1943             }
1944             sink(destfname, NULL);
1945             /* can we set the timestamp for directories ? */
1946             continue;
1947         }
1948
1949         f = CreateFile(destfname, GENERIC_WRITE, 0, NULL,
1950                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
1951         if (f == INVALID_HANDLE_VALUE) {
1952             run_err("%s: Cannot create file", destfname);
1953             continue;
1954         }
1955
1956         if (scp_accept_filexfer())
1957             return;
1958
1959         stat_bytes = 0;
1960         stat_starttime = time(NULL);
1961         stat_lasttime = 0;
1962         stat_name = stripslashes(destfname, 1);
1963
1964         received = 0;
1965         while (received < act.size) {
1966             char transbuf[4096];
1967             DWORD blksize, read, written;
1968             blksize = 4096;
1969             if (blksize > act.size - received)
1970                 blksize = act.size - received;
1971             read = scp_recv_filedata(transbuf, blksize);
1972             if (read <= 0)
1973                 bump("Lost connection");
1974             if (wrerror)
1975                 continue;
1976             if (!WriteFile(f, transbuf, read, &written, NULL) ||
1977                 written != read) {
1978                 wrerror = 1;
1979                 /* FIXME: in sftp we can actually abort the transfer */
1980                 if (statistics)
1981                     printf("\r%-25.25s | %50s\n",
1982                            stat_name,
1983                            "Write error.. waiting for end of file");
1984                 continue;
1985             }
1986             if (statistics) {
1987                 stat_bytes += read;
1988                 if (time(NULL) > stat_lasttime ||
1989                     received + read == act.size) {
1990                     stat_lasttime = time(NULL);
1991                     print_stats(stat_name, act.size, stat_bytes,
1992                                 stat_starttime, stat_lasttime);
1993                 }
1994             }
1995             received += read;
1996         }
1997         if (act.settime) {
1998             FILETIME actime, wrtime;
1999             TIME_POSIX_TO_WIN(act.atime, actime);
2000             TIME_POSIX_TO_WIN(act.mtime, wrtime);
2001             SetFileTime(f, NULL, &actime, &wrtime);
2002         }
2003
2004         CloseHandle(f);
2005         if (wrerror) {
2006             run_err("%s: Write error", destfname);
2007             continue;
2008         }
2009         (void) scp_finish_filerecv();
2010         sfree(destfname);
2011         sfree(act.buf);
2012     }
2013 }
2014
2015 /*
2016  * We will copy local files to a remote server.
2017  */
2018 static void toremote(int argc, char *argv[])
2019 {
2020     char *src, *targ, *host, *user;
2021     char *cmd;
2022     int i;
2023
2024     targ = argv[argc - 1];
2025
2026     /* Separate host from filename */
2027     host = targ;
2028     targ = colon(targ);
2029     if (targ == NULL)
2030         bump("targ == NULL in toremote()");
2031     *targ++ = '\0';
2032     if (*targ == '\0')
2033         targ = ".";
2034     /* Substitute "." for emtpy target */
2035
2036     /* Separate host and username */
2037     user = host;
2038     host = strrchr(host, '@');
2039     if (host == NULL) {
2040         host = user;
2041         user = NULL;
2042     } else {
2043         *host++ = '\0';
2044         if (*user == '\0')
2045             user = NULL;
2046     }
2047
2048     if (argc == 2) {
2049         /* Find out if the source filespec covers multiple files
2050            if so, we should set the targetshouldbedirectory flag */
2051         HANDLE fh;
2052         WIN32_FIND_DATA fdat;
2053         if (colon(argv[0]) != NULL)
2054             bump("%s: Remote to remote not supported", argv[0]);
2055         fh = FindFirstFile(argv[0], &fdat);
2056         if (fh == INVALID_HANDLE_VALUE)
2057             bump("%s: No such file or directory\n", argv[0]);
2058         if (FindNextFile(fh, &fdat))
2059             targetshouldbedirectory = 1;
2060         FindClose(fh);
2061     }
2062
2063     cmd = smalloc(strlen(targ) + 100);
2064     sprintf(cmd, "scp%s%s%s%s -t %s",
2065             verbose ? " -v" : "",
2066             recursive ? " -r" : "",
2067             preserve ? " -p" : "",
2068             targetshouldbedirectory ? " -d" : "", targ);
2069     do_cmd(host, user, cmd);
2070     sfree(cmd);
2071
2072     scp_source_setup(targ, targetshouldbedirectory);
2073
2074     for (i = 0; i < argc - 1; i++) {
2075         char *srcpath, *last;
2076         HANDLE dir;
2077         WIN32_FIND_DATA fdat;
2078         src = argv[i];
2079         if (colon(src) != NULL) {
2080             tell_user(stderr, "%s: Remote to remote not supported\n", src);
2081             errs++;
2082             continue;
2083         }
2084
2085         /*
2086          * Trim off the last pathname component of `src', to
2087          * provide the base pathname which will be prepended to
2088          * filenames returned from Find{First,Next}File.
2089          */
2090         srcpath = dupstr(src);
2091         last = stripslashes(srcpath, 1);
2092         *last = '\0';
2093
2094         dir = FindFirstFile(src, &fdat);
2095         if (dir == INVALID_HANDLE_VALUE) {
2096             run_err("%s: No such file or directory", src);
2097             continue;
2098         }
2099         do {
2100             char *filename;
2101             /*
2102              * Ensure that . and .. are never matched by wildcards,
2103              * but only by deliberate action.
2104              */
2105             if (!strcmp(fdat.cFileName, ".") ||
2106                 !strcmp(fdat.cFileName, "..")) {
2107                 /*
2108                  * Find*File has returned a special dir. We require
2109                  * that _either_ `src' ends in a backslash followed
2110                  * by that string, _or_ `src' is precisely that
2111                  * string.
2112                  */
2113                 int len = strlen(src), dlen = strlen(fdat.cFileName);
2114                 if (len == dlen && !strcmp(src, fdat.cFileName)) {
2115                     /* ok */ ;
2116                 } else if (len > dlen + 1 && src[len - dlen - 1] == '\\' &&
2117                            !strcmp(src + len - dlen, fdat.cFileName)) {
2118                     /* ok */ ;
2119                 } else
2120                     continue;          /* ignore this one */
2121             }
2122             filename = dupcat(srcpath, fdat.cFileName, NULL);
2123             source(filename);
2124             sfree(filename);
2125         } while (FindNextFile(dir, &fdat));
2126         FindClose(dir);
2127         sfree(srcpath);
2128     }
2129 }
2130
2131 /*
2132  *  We will copy files from a remote server to the local machine.
2133  */
2134 static void tolocal(int argc, char *argv[])
2135 {
2136     char *src, *targ, *host, *user;
2137     char *cmd;
2138
2139     if (argc != 2)
2140         bump("More than one remote source not supported");
2141
2142     src = argv[0];
2143     targ = argv[1];
2144
2145     /* Separate host from filename */
2146     host = src;
2147     src = colon(src);
2148     if (src == NULL)
2149         bump("Local to local copy not supported");
2150     *src++ = '\0';
2151     if (*src == '\0')
2152         src = ".";
2153     /* Substitute "." for empty filename */
2154
2155     /* Separate username and hostname */
2156     user = host;
2157     host = strrchr(host, '@');
2158     if (host == NULL) {
2159         host = user;
2160         user = NULL;
2161     } else {
2162         *host++ = '\0';
2163         if (*user == '\0')
2164             user = NULL;
2165     }
2166
2167     cmd = smalloc(strlen(src) + 100);
2168     sprintf(cmd, "scp%s%s%s%s -f %s",
2169             verbose ? " -v" : "",
2170             recursive ? " -r" : "",
2171             preserve ? " -p" : "",
2172             targetshouldbedirectory ? " -d" : "", src);
2173     do_cmd(host, user, cmd);
2174     sfree(cmd);
2175
2176     if (scp_sink_setup(src, preserve, recursive))
2177         return;
2178
2179     sink(targ, src);
2180 }
2181
2182 /*
2183  *  We will issue a list command to get a remote directory.
2184  */
2185 static void get_dir_list(int argc, char *argv[])
2186 {
2187     char *src, *host, *user;
2188     char *cmd, *p, *q;
2189     char c;
2190
2191     src = argv[0];
2192
2193     /* Separate host from filename */
2194     host = src;
2195     src = colon(src);
2196     if (src == NULL)
2197         bump("Local to local copy not supported");
2198     *src++ = '\0';
2199     if (*src == '\0')
2200         src = ".";
2201     /* Substitute "." for empty filename */
2202
2203     /* Separate username and hostname */
2204     user = host;
2205     host = strrchr(host, '@');
2206     if (host == NULL) {
2207         host = user;
2208         user = NULL;
2209     } else {
2210         *host++ = '\0';
2211         if (*user == '\0')
2212             user = NULL;
2213     }
2214
2215     cmd = smalloc(4 * strlen(src) + 100);
2216     strcpy(cmd, "ls -la '");
2217     p = cmd + strlen(cmd);
2218     for (q = src; *q; q++) {
2219         if (*q == '\'') {
2220             *p++ = '\'';
2221             *p++ = '\\';
2222             *p++ = '\'';
2223             *p++ = '\'';
2224         } else {
2225             *p++ = *q;
2226         }
2227     }
2228     *p++ = '\'';
2229     *p = '\0';
2230
2231     do_cmd(host, user, cmd);
2232     sfree(cmd);
2233
2234     if (using_sftp) {
2235         scp_sftp_listdir(src);
2236     } else {
2237         while (ssh_scp_recv(&c, 1) > 0)
2238             tell_char(stdout, c);
2239     }
2240 }
2241
2242 /*
2243  *  Initialize the Win$ock driver.
2244  */
2245 static void init_winsock(void)
2246 {
2247     WORD winsock_ver;
2248     WSADATA wsadata;
2249
2250     winsock_ver = MAKEWORD(1, 1);
2251     if (WSAStartup(winsock_ver, &wsadata))
2252         bump("Unable to initialise WinSock");
2253     if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1)
2254         bump("WinSock version is incompatible with 1.1");
2255 }
2256
2257 /*
2258  *  Short description of parameters.
2259  */
2260 static void usage(void)
2261 {
2262     printf("PuTTY Secure Copy client\n");
2263     printf("%s\n", ver);
2264     printf("Usage: pscp [options] [user@]host:source target\n");
2265     printf
2266         ("       pscp [options] source [source...] [user@]host:target\n");
2267     printf("       pscp [options] -ls user@host:filespec\n");
2268     printf("Options:\n");
2269     printf("  -p        preserve file attributes\n");
2270     printf("  -q        quiet, don't show statistics\n");
2271     printf("  -r        copy directories recursively\n");
2272     printf("  -v        show verbose messages\n");
2273     printf("  -P port   connect to specified port\n");
2274     printf("  -pw passw login with specified password\n");
2275     printf("  -unsafe   allow server-side wildcards (DANGEROUS)\n");
2276 #if 0
2277     /*
2278      * -gui is an internal option, used by GUI front ends to get
2279      * pscp to pass progress reports back to them. It's not an
2280      * ordinary user-accessible option, so it shouldn't be part of
2281      * the command-line help. The only people who need to know
2282      * about it are programmers, and they can read the source.
2283      */
2284     printf
2285         ("  -gui hWnd GUI mode with the windows handle for receiving messages\n");
2286 #endif
2287     exit(1);
2288 }
2289
2290 /*
2291  *  Main program (no, really?)
2292  */
2293 int main(int argc, char *argv[])
2294 {
2295     int i;
2296
2297     default_protocol = PROT_TELNET;
2298
2299     flags = FLAG_STDERR;
2300     ssh_get_line = &get_line;
2301     init_winsock();
2302     sk_init();
2303
2304     for (i = 1; i < argc; i++) {
2305         if (argv[i][0] != '-')
2306             break;
2307         if (strcmp(argv[i], "-v") == 0)
2308             verbose = 1, flags |= FLAG_VERBOSE;
2309         else if (strcmp(argv[i], "-r") == 0)
2310             recursive = 1;
2311         else if (strcmp(argv[i], "-p") == 0)
2312             preserve = 1;
2313         else if (strcmp(argv[i], "-q") == 0)
2314             statistics = 0;
2315         else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0)
2316             usage();
2317         else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc)
2318             portnumber = atoi(argv[++i]);
2319         else if (strcmp(argv[i], "-pw") == 0 && i + 1 < argc)
2320             password = argv[++i];
2321         else if (strcmp(argv[i], "-gui") == 0 && i + 1 < argc) {
2322             gui_hwnd = argv[++i];
2323             gui_mode = 1;
2324         } else if (strcmp(argv[i], "-ls") == 0)
2325             list = 1;
2326         else if (strcmp(argv[i], "-unsafe") == 0)
2327             scp_unsafe_mode = 1;
2328         else if (strcmp(argv[i], "--") == 0) {
2329             i++;
2330             break;
2331         } else
2332             usage();
2333     }
2334     argc -= i;
2335     argv += i;
2336     back = NULL;
2337
2338     if (list) {
2339         if (argc != 1)
2340             usage();
2341         get_dir_list(argc, argv);
2342
2343     } else {
2344
2345         if (argc < 2)
2346             usage();
2347         if (argc > 2)
2348             targetshouldbedirectory = 1;
2349
2350         if (colon(argv[argc - 1]) != NULL)
2351             toremote(argc, argv);
2352         else
2353             tolocal(argc, argv);
2354     }
2355
2356     if (back != NULL && back->socket() != NULL) {
2357         char ch;
2358         back->special(TS_EOF);
2359         ssh_scp_recv(&ch, 1);
2360     }
2361     WSACleanup();
2362     random_save_seed();
2363
2364     /* GUI Adaptation - August 2000 */
2365     if (gui_mode) {
2366         unsigned int msg_id = WM_RET_ERR_CNT;
2367         if (list)
2368             msg_id = WM_LS_RET_ERR_CNT;
2369         while (!PostMessage
2370                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
2371                 0 /*lParam */ ))SleepEx(1000, TRUE);
2372     }
2373     return (errs == 0 ? 0 : 1);
2374 }
2375
2376 /* end */