Retired the #ifdef DUMP_PACKETS stuff in ssh.c because I'm utterly
[u/mdw/putty] / 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 */