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