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