2 * scp.c - Scp (Secure Copy) client for PuTTY.
3 * Joris van Rantwijk, Simon Tatham
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.
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.)
30 #define PUTTY_DO_GLOBALS
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))
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 )
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;
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;
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);
93 * The maximum amount of queued data we accept before we stop and
94 * wait for the server to process some.
96 #define MAX_SCP_BUFSIZE 16384
98 void logevent(char *string)
102 void ldisc_send(char *buf, int len, int interactive)
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
113 void verify_ssh_host_key(char *host, int port, char *keytype,
114 char *keystr, char *fingerprint)
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"
124 "The server's key fingerprint is:\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"
132 "Store key in cache? (y/n) ";
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"
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"
150 "Update cached key? (y/n, Return cancels connection) ";
152 static const char abandoned[] = "Connection abandoned.\n";
157 * Verify the key against the registry.
159 ret = verify_host_key(host, port, keytype, keystr);
161 if (ret == 0) /* success - key matched OK */
164 if (ret == 2) { /* key was different */
165 fprintf(stderr, wrongmsg, fingerprint);
168 if (ret == 1) { /* key was absent */
169 fprintf(stderr, absentmsg, fingerprint);
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);
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);
184 fprintf(stderr, abandoned);
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
194 void askcipher(char *ciphername, int cs)
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";
209 (cs == 1) ? "client-to-server " :
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);
221 if (line[0] == 'y' || line[0] == 'Y') {
224 fprintf(stderr, abandoned);
230 * Warn about the obsolescent key file format.
232 void old_keyfile_warning(void)
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"
242 "Once the key is loaded into PuTTYgen, you can perform\n"
243 "this conversion simply by saving it again.\n";
245 fputs(message, stderr);
248 /* GUI Adaptation - Sept 2000 */
249 static void send_msg(HWND h, UINT message, WPARAM wParam)
251 while (!PostMessage(h, message, wParam, 0))
255 static void tell_char(FILE * stream, char c)
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);
267 static void tell_str(FILE * stream, char *str)
271 for (i = 0; i < strlen(str); ++i)
272 tell_char(stream, str[i]);
275 static void tell_user(FILE * stream, char *fmt, ...)
277 char str[0x100]; /* Make the size big enough */
280 vsprintf(str, fmt, ap);
283 tell_str(stream, str);
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)
293 if (strcmp(name, statname) != 0) {
294 for (i = 0; i < strlen(name); ++i)
295 send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR,
297 send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR, (WPARAM) '\n');
298 strcpy(statname, name);
300 if (statsize != size) {
301 send_msg((HWND) atoi(gui_hwnd), WM_STATS_SIZE, (WPARAM) size);
304 if (statdone != done) {
305 send_msg((HWND) atoi(gui_hwnd), WM_STATS_DONE, (WPARAM) done);
308 if (stateta != eta) {
309 send_msg((HWND) atoi(gui_hwnd), WM_STATS_ETA, (WPARAM) eta);
312 if (statratebs != ratebs) {
313 send_msg((HWND) atoi(gui_hwnd), WM_STATS_RATEBS, (WPARAM) ratebs);
316 if (statelapsed != elapsed) {
317 send_msg((HWND) atoi(gui_hwnd), WM_STATS_ELAPSED,
319 statelapsed = elapsed;
321 if (statperct != percentage) {
322 send_msg((HWND) atoi(gui_hwnd), WM_STATS_PERCENT,
323 (WPARAM) percentage);
324 statperct = percentage;
329 * Print an error message and perform a fatal exit.
331 void fatalbox(char *fmt, ...)
333 char str[0x100]; /* Make the size big enough */
336 strcpy(str, "Fatal: ");
337 vsprintf(str + strlen(str), fmt, ap);
340 tell_str(stderr, str);
344 unsigned int msg_id = WM_RET_ERR_CNT;
346 msg_id = WM_LS_RET_ERR_CNT;
348 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
349 0 /*lParam */ ))SleepEx(1000, TRUE);
354 void connection_fatal(char *fmt, ...)
356 char str[0x100]; /* Make the size big enough */
359 strcpy(str, "Fatal: ");
360 vsprintf(str + strlen(str), fmt, ap);
363 tell_str(stderr, str);
367 unsigned int msg_id = WM_RET_ERR_CNT;
369 msg_id = WM_LS_RET_ERR_CNT;
371 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
372 0 /*lParam */ ))SleepEx(1000, TRUE);
379 * Be told what socket we're supposed to be using.
381 static SOCKET scp_ssh_socket;
382 char *do_select(SOCKET skt, int startup)
385 scp_ssh_socket = skt;
387 scp_ssh_socket = INVALID_SOCKET;
390 extern int select_result(WPARAM, LPARAM);
393 * Receive a block of data from the SSH link. Block until all data
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.
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)
407 unsigned char *p = (unsigned char *) data;
408 unsigned len = (unsigned) datalen;
411 * stderr data is just spouted to local stderr and otherwise
415 fwrite(data, 1, len, stderr);
420 * If this is before the real session begins, just return.
426 unsigned used = outlen;
429 memcpy(outptr, p, used);
437 if (pendsize < pendlen + len) {
438 pendsize = pendlen + len + 4096;
439 pending = (pending ? srealloc(pending, pendsize) :
442 fatalbox("Out of memory");
444 memcpy(pending + pendlen, p, len);
450 static int scp_process_network_event(void)
455 FD_SET(scp_ssh_socket, &readfds);
456 if (select(1, &readfds, NULL, NULL, NULL) < 0)
458 select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
461 static int ssh_scp_recv(unsigned char *buf, int len)
467 * See if the pending-input block contains some of what we
471 unsigned pendused = pendlen;
472 if (pendused > outlen)
474 memcpy(outptr, pending, pendused);
475 memmove(pending, pending + pendused, pendlen - pendused);
489 if (!scp_process_network_event())
497 * Loop through the ssh connection and authentication process.
499 static void ssh_scp_init(void)
501 if (scp_ssh_socket == INVALID_SOCKET)
503 while (!back->sendok()) {
506 FD_SET(scp_ssh_socket, &readfds);
507 if (select(1, &readfds, NULL, NULL, NULL) < 0)
509 select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
511 using_sftp = !ssh_fallback_cmd;
515 * Print an error message and exit after closing the SSH link.
517 static void bump(char *fmt, ...)
519 char str[0x100]; /* Make the size big enough */
522 strcpy(str, "Fatal: ");
523 vsprintf(str + strlen(str), fmt, ap);
526 tell_str(stderr, str);
529 if (back != NULL && back->socket() != NULL) {
531 back->special(TS_EOF);
532 ssh_scp_recv(&ch, 1);
536 unsigned int msg_id = WM_RET_ERR_CNT;
538 msg_id = WM_LS_RET_ERR_CNT;
540 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
541 0 /*lParam */ ))SleepEx(1000, TRUE);
547 static int get_line(const char *prompt, char *str, int maxlen, int is_pw)
550 DWORD savemode, newmode, i;
552 if (is_pw && password) {
553 static int tried_once = 0;
558 strncpy(str, password, maxlen);
559 str[maxlen - 1] = '\0';
565 /* GUI Adaptation - Sept 2000 */
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");
575 GetConsoleMode(hin, &savemode);
576 newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
578 newmode &= ~ENABLE_ECHO_INPUT;
580 newmode |= ENABLE_ECHO_INPUT;
581 SetConsoleMode(hin, newmode);
583 WriteFile(hout, prompt, strlen(prompt), &i, NULL);
584 ReadFile(hin, str, maxlen - 1, &i, NULL);
586 SetConsoleMode(hin, savemode);
588 if ((int) i > maxlen)
595 WriteFile(hout, "\r\n", 2, &i, NULL);
602 * Open an SSH connection to user@host and execute cmd.
604 static void do_cmd(char *host, char *user, char *cmd)
606 char *err, *realhost;
609 if (host == NULL || host[0] == '\0')
610 bump("Empty host name");
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';
623 * Trim leading whitespace off the hostname if it's there.
626 int space = strspn(cfg.host, " \t");
627 memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
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 */
635 if (atsign - cfg.host < sizeof cfg.username) {
636 strncpy(cfg.username, cfg.host, atsign - cfg.host);
637 cfg.username[atsign - cfg.host] = '\0';
639 memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));
644 * Trim a colon suffix off the hostname if it's there.
646 cfg.host[strcspn(cfg.host, ":")] = '\0';
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') {
654 if (GetUserName(user, &namelen) == FALSE)
655 bump("Empty user name");
656 user = smalloc(namelen * sizeof(char));
657 GetUserName(user, &namelen);
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';
665 if (cfg.protocol != PROT_SSH)
669 cfg.port = portnumber;
672 * Disable scary things which shouldn't be enabled for simple
673 * things like SCP and SFTP: agent forwarding, port forwarding,
678 cfg.portfwd[0] = cfg.portfwd[1] = '\0';
681 * Attempt to start the SFTP subsystem as a first choice,
682 * falling back to the provided scp command if that fails.
684 strcpy(cfg.remote_cmd, "sftp");
685 cfg.ssh_subsys = TRUE;
686 cfg.remote_cmd_ptr2 = cmd;
687 cfg.ssh_subsys2 = FALSE;
692 err = back->init(cfg.host, cfg.port, &realhost, 0);
694 bump("ssh_init: %s", err);
696 if (verbose && realhost != NULL)
697 tell_user(stderr, "Connected to %s\n", realhost);
702 * Update statistic information about current file.
704 static void print_stats(char *name, unsigned long size, unsigned long done,
705 time_t start, time_t now)
714 elap = (unsigned long) difftime(now, start);
717 ratebs = (float) done / elap;
719 ratebs = (float) done;
724 eta = (unsigned long) ((size - done) / ratebs);
725 sprintf(etastr, "%02ld:%02ld:%02ld",
726 eta / 3600, (eta % 3600) / 60, eta % 60);
728 pct = (int) (100 * (done * 1.0 / size));
731 /* GUI Adaptation - Sept 2000 */
732 gui_update_stats(name, size, pct, elap, done, eta,
733 (unsigned long) ratebs);
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;
747 * Find a colon in str and return a pointer to the colon.
748 * This is used to separate hostname from filename.
750 static char *colon(char *str)
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] == ':')
757 while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\')
766 * Return a pointer to the portion of str that comes after the last
767 * slash (or backslash or colon, if `local' is TRUE).
769 static char *stripslashes(char *str, int local)
774 p = strchr(str, ':');
778 p = strrchr(str, '/');
782 p = strrchr(str, '\\');
790 * Determine whether a string is entirely composed of dots.
792 static int is_dots(char *str)
794 return str[strspn(str, ".")] == '\0';
798 * Wait for a response from the other side.
799 * Return 0 if ok, -1 if error.
801 static int response(void)
803 char ch, resp, rbuf[2048];
806 if (ssh_scp_recv(&resp, 1) <= 0)
807 bump("Lost connection");
817 case 2: /* fatal error */
819 if (ssh_scp_recv(&ch, 1) <= 0)
820 bump("Protocol error: Lost connection");
822 } while (p < sizeof(rbuf) && ch != '\n');
825 tell_user(stderr, "%s\n", rbuf);
833 int sftp_recvdata(char *buf, int len)
835 return ssh_scp_recv(buf, len);
837 int sftp_senddata(char *buf, int len)
839 back->send((unsigned char *) buf, len);
843 /* ----------------------------------------------------------------------
844 * sftp-based replacement for the hacky `pscp -ls'.
846 static int sftp_ls_compare(const void *av, const void *bv)
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);
852 void scp_sftp_listdir(char *dirname)
854 struct fxp_handle *dirh;
855 struct fxp_names *names;
856 struct fxp_name *ournames;
857 int nnames, namesize;
860 printf("Listing directory %s\n", dirname);
862 dirh = fxp_opendir(dirname);
864 printf("Unable to open %s: %s\n", dirname, fxp_error());
866 nnames = namesize = 0;
871 names = fxp_readdir(dirh);
873 if (fxp_error_type() == SSH_FX_EOF)
875 printf("Reading directory %s: %s\n", dirname, fxp_error());
878 if (names->nnames == 0) {
879 fxp_free_names(names);
883 if (nnames + names->nnames >= namesize) {
884 namesize += names->nnames + 128;
886 srealloc(ournames, namesize * sizeof(*ournames));
889 for (i = 0; i < names->nnames; i++)
890 ournames[nnames++] = names->names[i];
892 names->nnames = 0; /* prevent free_names */
893 fxp_free_names(names);
898 * Now we have our filenames. Sort them by actual file
899 * name, and then output the longname parts.
901 qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);
906 for (i = 0; i < nnames; i++)
907 printf("%s\n", ournames[i].longname);
911 /* ----------------------------------------------------------------------
912 * Helper routines that contain the actual SCP protocol elements,
913 * implemented both as SCP1 and SFTP.
916 static struct scp_sftp_dirstack {
917 struct scp_sftp_dirstack *next;
918 struct fxp_name *names;
919 int namepos, namelen;
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;
933 void scp_source_setup(char *target, int shouldbedir)
937 * Find out whether the target filespec is in fact a
940 struct fxp_attrs attrs;
942 if (!fxp_stat(target, &attrs) ||
943 !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS))
944 scp_sftp_targetisdir = 0;
946 scp_sftp_targetisdir = (attrs.permissions & 0040000) != 0;
948 if (shouldbedir && !scp_sftp_targetisdir) {
949 bump("pscp: remote filespec %s: not a directory\n", target);
952 scp_sftp_remotepath = dupstr(target);
960 int scp_send_errmsg(char *str)
963 /* do nothing; we never need to send our errors to the server */
965 back->send("\001", 1); /* scp protocol error prefix */
966 back->send(str, strlen(str));
968 return 0; /* can't fail */
971 int scp_send_filetimes(unsigned long mtime, unsigned long atime)
974 scp_sftp_mtime = mtime;
975 scp_sftp_atime = atime;
980 sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
981 back->send(buf, strlen(buf));
986 int scp_send_filename(char *name, unsigned long size, int modes)
990 if (scp_sftp_targetisdir) {
991 fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
993 fullname = dupstr(scp_sftp_remotepath);
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());
1003 scp_sftp_fileoffset = uint64_make(0, 0);
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);
1016 int scp_send_filedata(char *data, int len)
1019 if (!scp_sftp_filehandle) {
1022 if (!fxp_write(scp_sftp_filehandle, data, scp_sftp_fileoffset, len)) {
1023 tell_user(stderr, "error while writing: %s\n", fxp_error());
1027 scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len);
1030 int bufsize = back->send(data, len);
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.
1038 while (bufsize > MAX_SCP_BUFSIZE) {
1039 if (!scp_process_network_event())
1041 bufsize = back->sendbuffer();
1048 int scp_send_finish(void)
1051 struct fxp_attrs attrs;
1052 if (!scp_sftp_filehandle) {
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());
1064 fxp_close(scp_sftp_filehandle);
1073 char *scp_save_remotepath(void)
1076 return scp_sftp_remotepath;
1081 void scp_restore_remotepath(char *data)
1084 scp_sftp_remotepath = data;
1087 int scp_send_dirname(char *name, int modes)
1092 struct fxp_attrs attrs;
1093 if (scp_sftp_targetisdir) {
1094 fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
1096 fullname = dupstr(scp_sftp_remotepath);
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.
1106 if (!fxp_mkdir(fullname))
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",
1119 scp_sftp_remotepath = fullname;
1124 sprintf(buf, "D%04o 0 ", modes);
1125 back->send(buf, strlen(buf));
1126 back->send(name, strlen(name));
1127 back->send("\n", 1);
1132 int scp_send_enddir(void)
1135 sfree(scp_sftp_remotepath);
1138 back->send("E\n", 2);
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.
1149 int scp_sink_setup(char *source, int preserve, int recursive)
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.
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);
1168 if (*dupsource && dupsource[1]) {
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
1175 lastpart[-1] = '\0';
1176 } else if (!*dupsource) {
1178 * The remains of dupsource are _empty_ - the whole
1179 * pathname was a wildcard. Hence we need to
1180 * replace it with ".".
1183 dupsource = dupstr(".");
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.
1193 dirpart = smalloc(1+strlen(dupsource));
1194 if (!wc_unescape(dirpart, dupsource)) {
1195 tell_user(stderr, "%s: multiple-level wildcards unsupported",
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.
1209 scp_sftp_remotepath = dirpart;
1210 scp_sftp_wildcard = wildcard;
1213 scp_sftp_remotepath = newsource;
1214 scp_sftp_wildcard = NULL;
1216 scp_sftp_preserve = preserve;
1217 scp_sftp_recursive = recursive;
1218 scp_sftp_donethistarget = 0;
1219 scp_sftp_dirstack_head = NULL;
1224 int scp_sink_init(void)
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 */
1246 int scp_get_sink_action(struct scp_sink_action *act)
1250 int must_free_fname;
1251 struct fxp_attrs attrs;
1254 if (!scp_sftp_dirstack_head) {
1255 if (!scp_sftp_donethistarget) {
1257 * Simple case: we are only dealing with one file.
1259 fname = scp_sftp_remotepath;
1260 must_free_fname = 0;
1261 scp_sftp_donethistarget = 1;
1264 * Even simpler case: one file _which we've done_.
1265 * Return 1 (finished).
1271 * We're now in the middle of stepping through a list
1272 * of names returned from fxp_readdir(); so let's carry
1275 struct scp_sftp_dirstack *head = scp_sftp_dirstack_head;
1276 while (head->namepos < head->namelen &&
1277 (is_dots(head->names[head->namepos].filename) ||
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,
1287 must_free_fname = 1;
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).
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);
1301 sfree(head->wildcard);
1304 act->action = SCP_SINK_ENDDIR;
1307 sfree(head->dirpath);
1309 scp_sftp_dirstack_head = head->next;
1317 * Now we have a filename. Stat it, and see if it's a file
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());
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;
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
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.
1347 if (!scp_sftp_recursive && !scp_sftp_wildcard) {
1348 tell_user(stderr, "pscp: %s: is a directory", fname);
1350 if (must_free_fname) sfree(fname);
1351 if (scp_sftp_dirstack_head) {
1352 act->action = SCP_SINK_RETRY;
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.
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
1372 dirhandle = fxp_opendir(fname);
1374 tell_user(stderr, "scp: unable to open directory %s: %s",
1375 fname, fxp_error());
1376 if (must_free_fname) sfree(fname);
1380 nnames = namesize = 0;
1385 names = fxp_readdir(dirhandle);
1386 if (names == NULL) {
1387 if (fxp_error_type() == SSH_FX_EOF)
1389 tell_user(stderr, "scp: reading directory %s: %s\n",
1390 fname, fxp_error());
1391 if (must_free_fname) sfree(fname);
1396 if (names->nnames == 0) {
1397 fxp_free_names(names);
1400 if (nnames + names->nnames >= namesize) {
1401 namesize += names->nnames + 128;
1403 srealloc(ournames, namesize * sizeof(*ournames));
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);
1410 fxp_close(dirhandle);
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;
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;
1426 newitem->wildcard = NULL;
1428 scp_sftp_dirstack_head = newitem;
1430 if (newitem->wildcard) {
1431 act->action = SCP_SINK_RETRY;
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;
1450 * It's a file. Return SCP_SINK_FILE.
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* */
1460 act->size = attrs.size.lo;
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;
1471 if (must_free_fname)
1472 scp_sftp_currentname = fname;
1474 scp_sftp_currentname = dupstr(fname);
1489 if (ssh_scp_recv(&ch, 1) <= 0)
1492 bump("Protocol error: Unexpected newline");
1496 if (ssh_scp_recv(&ch, 1) <= 0)
1497 bump("Lost connection");
1500 act->buf = srealloc(act->buf, bufsize);
1503 } while (ch != '\n');
1504 act->buf[i - 1] = '\0';
1506 case '\01': /* error */
1507 tell_user(stderr, "%s\n", act->buf);
1509 continue; /* go round again */
1510 case '\02': /* fatal error */
1511 bump("%s", act->buf);
1514 act->action = SCP_SINK_ENDDIR;
1517 if (sscanf(act->buf, "%ld %*d %ld %*d",
1518 &act->mtime, &act->atime) == 2) {
1521 continue; /* go round again */
1523 bump("Protocol error: Illegal time format");
1526 act->action = (action == 'C' ? SCP_SINK_FILE : SCP_SINK_DIR);
1529 bump("Protocol error: Expected control record");
1532 * We will go round this loop only once, unless we hit
1539 * If we get here, we must have seen SCP_SINK_FILE or
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;
1549 int scp_accept_filexfer(void)
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());
1560 scp_sftp_fileoffset = uint64_make(0, 0);
1561 sfree(scp_sftp_currentname);
1565 return 0; /* can't fail */
1569 int scp_recv_filedata(char *data, int len)
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());
1582 scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, actuallen);
1586 return ssh_scp_recv(data, len);
1590 int scp_finish_filerecv(void)
1593 fxp_close(scp_sftp_filehandle);
1601 /* ----------------------------------------------------------------------
1602 * Send an error message to the other side and to the screen.
1603 * Increment error counter.
1605 static void run_err(const char *fmt, ...)
1611 strcpy(str, "scp: ");
1612 vsprintf(str + strlen(str), fmt, ap);
1614 scp_send_errmsg(str);
1615 tell_user(stderr, "%s", str);
1620 * Execute the source part of the SCP protocol.
1622 static void source(char *src)
1629 unsigned long stat_bytes;
1630 time_t stat_starttime, stat_lasttime;
1632 attr = GetFileAttributes(src);
1633 if (attr == (DWORD) - 1) {
1634 run_err("%s: No such file or directory", src);
1638 if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1641 * Avoid . and .. directories.
1644 p = strrchr(src, '/');
1646 p = strrchr(src, '\\');
1651 if (!strcmp(p, ".") || !strcmp(p, ".."))
1652 /* skip . and .. */ ;
1656 run_err("%s: not a regular file", src);
1661 if ((last = strrchr(src, '/')) == NULL)
1665 if (strrchr(last, '\\') != NULL)
1666 last = strrchr(last, '\\') + 1;
1667 if (last == src && strchr(src, ':') != NULL)
1668 last = strchr(src, ':') + 1;
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);
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))
1687 size = GetFileSize(f, NULL);
1689 tell_user(stderr, "Sending file %s, size=%lu", last, size);
1690 if (scp_send_filename(last, size, 0644))
1694 stat_starttime = time(NULL);
1697 for (i = 0; i < size; i += 4096) {
1698 char transbuf[4096];
1703 if (!ReadFile(f, transbuf, k, &j, NULL) || j != k) {
1706 bump("%s: Read error", src);
1708 if (scp_send_filedata(transbuf, k))
1709 bump("%s: Network error occurred", src);
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);
1723 (void) scp_send_finish();
1727 * Recursively send the contents of a directory.
1729 static void rsource(char *src)
1731 char *last, *findfile;
1734 WIN32_FIND_DATA fdat;
1737 if ((last = strrchr(src, '/')) == NULL)
1741 if (strrchr(last, '\\') != NULL)
1742 last = strrchr(last, '\\') + 1;
1743 if (last == src && strchr(src, ':') != NULL)
1744 last = strchr(src, ':') + 1;
1746 /* maybe send filetime */
1748 save_target = scp_save_remotepath();
1751 tell_user(stderr, "Entering directory: %s", last);
1752 if (scp_send_dirname(last, 0755))
1755 findfile = dupcat(src, "/*", NULL);
1756 dir = FindFirstFile(findfile, &fdat);
1757 ok = (dir != INVALID_HANDLE_VALUE);
1759 if (strcmp(fdat.cFileName, ".") == 0 ||
1760 strcmp(fdat.cFileName, "..") == 0) {
1761 /* ignore . and .. */
1763 char *foundfile = dupcat(src, "/", fdat.cFileName, NULL);
1767 ok = FindNextFile(dir, &fdat);
1772 (void) scp_send_enddir();
1774 scp_restore_remotepath(save_target);
1778 * Execute the sink part of the SCP protocol.
1780 static void sink(char *targ, char *src)
1787 unsigned long received;
1789 unsigned long stat_bytes;
1790 time_t stat_starttime, stat_lasttime;
1793 attr = GetFileAttributes(targ);
1794 if (attr != (DWORD) - 1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
1797 if (targetshouldbedirectory && !targisdir)
1798 bump("%s: Not a directory", targ);
1802 struct scp_sink_action act;
1803 if (scp_get_sink_action(&act))
1806 if (act.action == SCP_SINK_ENDDIR)
1809 if (act.action == SCP_SINK_RETRY)
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
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.
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
1843 char *striptarget, *stripsrc;
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'",
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 '..'.
1858 if (is_dots(striptarget)) {
1859 bump("security violation: remote host attempted to write to"
1860 " a '.' or '..' path!");
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;
1880 if (targ[0] != '\0')
1881 destfname = dupcat(targ, "\\", striptarget, NULL);
1883 destfname = dupstr(striptarget);
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.
1890 destfname = dupstr(targ);
1892 attr = GetFileAttributes(destfname);
1893 exists = (attr != (DWORD) - 1);
1895 if (act.action == SCP_SINK_DIR) {
1896 if (exists && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
1897 run_err("%s: Not a directory", destfname);
1901 if (!CreateDirectory(destfname, NULL)) {
1902 run_err("%s: Cannot create directory", destfname);
1906 sink(destfname, NULL);
1907 /* can we set the timestamp for directories ? */
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);
1918 if (scp_accept_filexfer())
1922 stat_starttime = time(NULL);
1924 stat_name = stripslashes(destfname, 1);
1927 while (received < act.size) {
1928 char transbuf[4096];
1929 DWORD blksize, read, written;
1931 if (blksize > act.size - received)
1932 blksize = act.size - received;
1933 read = scp_recv_filedata(transbuf, blksize);
1935 bump("Lost connection");
1938 if (!WriteFile(f, transbuf, read, &written, NULL) ||
1941 /* FIXME: in sftp we can actually abort the transfer */
1943 printf("\r%-25.25s | %50s\n",
1945 "Write error.. waiting for end of file");
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);
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);
1968 run_err("%s: Write error", destfname);
1971 (void) scp_finish_filerecv();
1978 * We will copy local files to a remote server.
1980 static void toremote(int argc, char *argv[])
1982 char *src, *targ, *host, *user;
1986 targ = argv[argc - 1];
1988 /* Separate host from filename */
1992 bump("targ == NULL in toremote()");
1996 /* Substitute "." for emtpy target */
1998 /* Separate host and username */
2000 host = strrchr(host, '@');
2011 /* Find out if the source filespec covers multiple files
2012 if so, we should set the targetshouldbedirectory flag */
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;
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);
2034 scp_source_setup(targ, targetshouldbedirectory);
2036 for (i = 0; i < argc - 1; i++) {
2037 char *srcpath, *last;
2039 WIN32_FIND_DATA fdat;
2041 if (colon(src) != NULL) {
2042 tell_user(stderr, "%s: Remote to remote not supported\n", src);
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.
2052 srcpath = dupstr(src);
2053 last = stripslashes(srcpath, 1);
2056 dir = FindFirstFile(src, &fdat);
2057 if (dir == INVALID_HANDLE_VALUE) {
2058 run_err("%s: No such file or directory", src);
2064 * Ensure that . and .. are never matched by wildcards,
2065 * but only by deliberate action.
2067 if (!strcmp(fdat.cFileName, ".") ||
2068 !strcmp(fdat.cFileName, "..")) {
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
2075 int len = strlen(src), dlen = strlen(fdat.cFileName);
2076 if (len == dlen && !strcmp(src, fdat.cFileName)) {
2078 } else if (len > dlen + 1 && src[len - dlen - 1] == '\\' &&
2079 !strcmp(src + len - dlen, fdat.cFileName)) {
2082 continue; /* ignore this one */
2084 filename = dupcat(srcpath, fdat.cFileName, NULL);
2087 } while (FindNextFile(dir, &fdat));
2094 * We will copy files from a remote server to the local machine.
2096 static void tolocal(int argc, char *argv[])
2098 char *src, *targ, *host, *user;
2102 bump("More than one remote source not supported");
2107 /* Separate host from filename */
2111 bump("Local to local copy not supported");
2115 /* Substitute "." for empty filename */
2117 /* Separate username and hostname */
2119 host = strrchr(host, '@');
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);
2138 if (scp_sink_setup(src, preserve, recursive))
2145 * We will issue a list command to get a remote directory.
2147 static void get_dir_list(int argc, char *argv[])
2149 char *src, *host, *user;
2155 /* Separate host from filename */
2159 bump("Local to local copy not supported");
2163 /* Substitute "." for empty filename */
2165 /* Separate username and hostname */
2167 host = strrchr(host, '@');
2177 cmd = smalloc(4 * strlen(src) + 100);
2178 strcpy(cmd, "ls -la '");
2179 p = cmd + strlen(cmd);
2180 for (q = src; *q; q++) {
2193 do_cmd(host, user, cmd);
2197 scp_sftp_listdir(src);
2199 while (ssh_scp_recv(&c, 1) > 0)
2200 tell_char(stdout, c);
2205 * Initialize the Win$ock driver.
2207 static void init_winsock(void)
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");
2220 * Short description of parameters.
2222 static void usage(void)
2224 printf("PuTTY Secure Copy client\n");
2225 printf("%s\n", ver);
2226 printf("Usage: pscp [options] [user@]host:source target\n");
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");
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.
2247 (" -gui hWnd GUI mode with the windows handle for receiving messages\n");
2253 * Main program (no, really?)
2255 int main(int argc, char *argv[])
2259 default_protocol = PROT_TELNET;
2261 flags = FLAG_STDERR;
2262 ssh_get_line = &get_line;
2266 for (i = 1; i < argc; i++) {
2267 if (argv[i][0] != '-')
2269 if (strcmp(argv[i], "-v") == 0)
2270 verbose = 1, flags |= FLAG_VERBOSE;
2271 else if (strcmp(argv[i], "-r") == 0)
2273 else if (strcmp(argv[i], "-p") == 0)
2275 else if (strcmp(argv[i], "-q") == 0)
2277 else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0)
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];
2286 } else if (strcmp(argv[i], "-ls") == 0)
2288 else if (strcmp(argv[i], "-unsafe") == 0)
2289 scp_unsafe_mode = 1;
2290 else if (strcmp(argv[i], "--") == 0) {
2303 get_dir_list(argc, argv);
2310 targetshouldbedirectory = 1;
2312 if (colon(argv[argc - 1]) != NULL)
2313 toremote(argc, argv);
2315 tolocal(argc, argv);
2318 if (back != NULL && back->socket() != NULL) {
2320 back->special(TS_EOF);
2321 ssh_scp_recv(&ch, 1);
2326 /* GUI Adaptation - August 2000 */
2328 unsigned int msg_id = WM_RET_ERR_CNT;
2330 msg_id = WM_LS_RET_ERR_CNT;
2332 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
2333 0 /*lParam */ ))SleepEx(1000, TRUE);
2335 return (errs == 0 ? 0 : 1);