scp.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  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. #include <windows.h>
  9. #include <winsock.h>
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <time.h>
  14. #define PUTTY_DO_GLOBALS
  15. #include "putty.h"
  16. #include "scp.h"
  17. #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
  18. ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
  19. #define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
  20. ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
  21. static int verbose = 0;
  22. static int recursive = 0;
  23. static int preserve = 0;
  24. static int targetshouldbedirectory = 0;
  25. static int statistics = 1;
  26. static int portnumber = 0;
  27. static char *password = NULL;
  28. static int errs = 0;
  29. static int connection_open = 0;
  30. static void source(char *src);
  31. static void rsource(char *src);
  32. static void sink(char *targ);
  33. /*
  34. * This function is needed to link with ssh.c, but it never gets called.
  35. */
  36. void term_out(void)
  37. {
  38. abort();
  39. }
  40. /*
  41. * Print an error message and perform a fatal exit.
  42. */
  43. void fatalbox(char *fmt, ...)
  44. {
  45. va_list ap;
  46. va_start(ap, fmt);
  47. fprintf(stderr, "Fatal: ");
  48. vfprintf(stderr, fmt, ap);
  49. fprintf(stderr, "\n");
  50. va_end(ap);
  51. exit(1);
  52. }
  53. /*
  54. * Print an error message and exit after closing the SSH link.
  55. */
  56. static void bump(char *fmt, ...)
  57. {
  58. va_list ap;
  59. va_start(ap, fmt);
  60. fprintf(stderr, "Fatal: ");
  61. vfprintf(stderr, fmt, ap);
  62. fprintf(stderr, "\n");
  63. va_end(ap);
  64. if (connection_open) {
  65. char ch;
  66. ssh_scp_send_eof();
  67. ssh_scp_recv(&ch, 1);
  68. }
  69. exit(1);
  70. }
  71. static void get_password(const char *prompt, char *str, int maxlen)
  72. {
  73. HANDLE hin, hout;
  74. DWORD savemode, i;
  75. if (password) {
  76. strncpy(str, password, maxlen);
  77. str[maxlen-1] = '\0';
  78. password = NULL;
  79. return;
  80. }
  81. hin = GetStdHandle(STD_INPUT_HANDLE);
  82. hout = GetStdHandle(STD_OUTPUT_HANDLE);
  83. if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE)
  84. bump("Cannot get standard input/output handles");
  85. GetConsoleMode(hin, &savemode);
  86. SetConsoleMode(hin, (savemode & (~ENABLE_ECHO_INPUT)) |
  87. ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT);
  88. WriteFile(hout, prompt, strlen(prompt), &i, NULL);
  89. ReadFile(hin, str, maxlen-1, &i, NULL);
  90. SetConsoleMode(hin, savemode);
  91. if ((int)i > maxlen) i = maxlen-1; else i = i - 2;
  92. str[i] = '\0';
  93. WriteFile(hout, "\r\n", 2, &i, NULL);
  94. }
  95. /*
  96. * Open an SSH connection to user@host and execute cmd.
  97. */
  98. static void do_cmd(char *host, char *user, char *cmd)
  99. {
  100. char *err, *realhost;
  101. if (host == NULL || host[0] == '\0')
  102. bump("Empty host name");
  103. /* Try to load settings for this host */
  104. do_defaults(host);
  105. if (cfg.host[0] == '\0') {
  106. /* No settings for this host; use defaults */
  107. strncpy(cfg.host, host, sizeof(cfg.host)-1);
  108. cfg.host[sizeof(cfg.host)-1] = '\0';
  109. cfg.port = 22;
  110. }
  111. /* Set username */
  112. if (user != NULL && user[0] != '\0') {
  113. strncpy(cfg.username, user, sizeof(cfg.username)-1);
  114. cfg.username[sizeof(cfg.username)-1] = '\0';
  115. } else if (cfg.username[0] == '\0') {
  116. bump("Empty user name");
  117. }
  118. if (cfg.protocol != PROT_SSH)
  119. cfg.port = 22;
  120. if (portnumber)
  121. cfg.port = portnumber;
  122. err = ssh_scp_init(cfg.host, cfg.port, cmd, &realhost);
  123. if (err != NULL)
  124. bump("ssh_init: %s", err);
  125. if (verbose && realhost != NULL)
  126. fprintf(stderr, "Connected to %s\n", realhost);
  127. connection_open = 1;
  128. }
  129. /*
  130. * Update statistic information about current file.
  131. */
  132. static void print_stats(char *name, unsigned long size, unsigned long done,
  133. time_t start, time_t now)
  134. {
  135. float ratebs;
  136. unsigned long eta;
  137. char etastr[10];
  138. int pct;
  139. if (now > start)
  140. ratebs = (float) done / (now - start);
  141. else
  142. ratebs = (float) done;
  143. if (ratebs < 1.0)
  144. eta = size - done;
  145. else
  146. eta = (unsigned long) ((size - done) / ratebs);
  147. sprintf(etastr, "%02ld:%02ld:%02ld",
  148. eta / 3600, (eta % 3600) / 60, eta % 60);
  149. pct = (int) (100.0 * (float) done / size);
  150. printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
  151. name, done / 1024, ratebs / 1024.0,
  152. etastr, pct);
  153. if (done == size)
  154. printf("\n");
  155. }
  156. /*
  157. * Find a colon in str and return a pointer to the colon.
  158. * This is used to separate hostname from filename.
  159. */
  160. static char * colon(char *str)
  161. {
  162. /* We ignore a leading colon, since the hostname cannot be
  163. empty. We also ignore a colon as second character because
  164. of filenames like f:myfile.txt. */
  165. if (str[0] == '\0' ||
  166. str[0] == ':' ||
  167. str[1] == ':')
  168. return (NULL);
  169. while (*str != '\0' &&
  170. *str != ':' &&
  171. *str != '/' &&
  172. *str != '\\')
  173. str++;
  174. if (*str == ':')
  175. return (str);
  176. else
  177. return (NULL);
  178. }
  179. /*
  180. * Wait for a response from the other side.
  181. * Return 0 if ok, -1 if error.
  182. */
  183. static int response(void)
  184. {
  185. char ch, resp, rbuf[2048];
  186. int p;
  187. if (ssh_scp_recv(&resp, 1) <= 0)
  188. bump("Lost connection");
  189. p = 0;
  190. switch (resp) {
  191. case 0: /* ok */
  192. return (0);
  193. default:
  194. rbuf[p++] = resp;
  195. /* fallthrough */
  196. case 1: /* error */
  197. case 2: /* fatal error */
  198. do {
  199. if (ssh_scp_recv(&ch, 1) <= 0)
  200. bump("Protocol error: Lost connection");
  201. rbuf[p++] = ch;
  202. } while (p < sizeof(rbuf) && ch != '\n');
  203. rbuf[p-1] = '\0';
  204. if (resp == 1)
  205. fprintf(stderr, "%s\n", rbuf);
  206. else
  207. bump("%s", rbuf);
  208. errs++;
  209. return (-1);
  210. }
  211. }
  212. /*
  213. * Send an error message to the other side and to the screen.
  214. * Increment error counter.
  215. */
  216. static void run_err(const char *fmt, ...)
  217. {
  218. char str[2048];
  219. va_list ap;
  220. va_start(ap, fmt);
  221. errs++;
  222. strcpy(str, "\01scp: ");
  223. vsprintf(str+strlen(str), fmt, ap);
  224. strcat(str, "\n");
  225. ssh_scp_send(str, strlen(str));
  226. vfprintf(stderr, fmt, ap);
  227. fprintf(stderr, "\n");
  228. va_end(ap);
  229. }
  230. /*
  231. * Execute the source part of the SCP protocol.
  232. */
  233. static void source(char *src)
  234. {
  235. char buf[2048];
  236. unsigned long size;
  237. char *last;
  238. HANDLE f;
  239. DWORD attr;
  240. unsigned long i;
  241. unsigned long stat_bytes;
  242. time_t stat_starttime, stat_lasttime;
  243. attr = GetFileAttributes(src);
  244. if (attr == (DWORD)-1) {
  245. run_err("%s: No such file or directory", src);
  246. return;
  247. }
  248. if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
  249. if (recursive) {
  250. /*
  251. * Avoid . and .. directories.
  252. */
  253. char *p;
  254. p = strrchr(src, '/');
  255. if (!p)
  256. p = strrchr(src, '\\');
  257. if (!p)
  258. p = src;
  259. else
  260. p++;
  261. if (!strcmp(p, ".") || !strcmp(p, ".."))
  262. /* skip . and .. */;
  263. else
  264. rsource(src);
  265. } else {
  266. run_err("%s: not a regular file", src);
  267. }
  268. return;
  269. }
  270. if ((last = strrchr(src, '/')) == NULL)
  271. last = src;
  272. else
  273. last++;
  274. if (strrchr(last, '\\') != NULL)
  275. last = strrchr(last, '\\') + 1;
  276. if (last == src && strchr(src, ':') != NULL)
  277. last = strchr(src, ':') + 1;
  278. f = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL,
  279. OPEN_EXISTING, 0, 0);
  280. if (f == INVALID_HANDLE_VALUE) {
  281. run_err("%s: Cannot open file", src);
  282. return;
  283. }
  284. if (preserve) {
  285. FILETIME actime, wrtime;
  286. unsigned long mtime, atime;
  287. GetFileTime(f, NULL, &actime, &wrtime);
  288. TIME_WIN_TO_POSIX(actime, atime);
  289. TIME_WIN_TO_POSIX(wrtime, mtime);
  290. sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
  291. ssh_scp_send(buf, strlen(buf));
  292. if (response())
  293. return;
  294. }
  295. size = GetFileSize(f, NULL);
  296. sprintf(buf, "C0644 %lu %s\n", size, last);
  297. if (verbose)
  298. fprintf(stderr, "Sending file modes: %s", buf);
  299. ssh_scp_send(buf, strlen(buf));
  300. if (response())
  301. return;
  302. if (statistics) {
  303. stat_bytes = 0;
  304. stat_starttime = time(NULL);
  305. stat_lasttime = 0;
  306. }
  307. for (i = 0; i < size; i += 4096) {
  308. char transbuf[4096];
  309. DWORD j, k = 4096;
  310. if (i + k > size) k = size - i;
  311. if (! ReadFile(f, transbuf, k, &j, NULL) || j != k) {
  312. if (statistics) printf("\n");
  313. bump("%s: Read error", src);
  314. }
  315. ssh_scp_send(transbuf, k);
  316. if (statistics) {
  317. stat_bytes += k;
  318. if (time(NULL) != stat_lasttime ||
  319. i + k == size) {
  320. stat_lasttime = time(NULL);
  321. print_stats(last, size, stat_bytes,
  322. stat_starttime, stat_lasttime);
  323. }
  324. }
  325. }
  326. CloseHandle(f);
  327. ssh_scp_send("", 1);
  328. (void) response();
  329. }
  330. /*
  331. * Recursively send the contents of a directory.
  332. */
  333. static void rsource(char *src)
  334. {
  335. char buf[2048];
  336. char *last;
  337. HANDLE dir;
  338. WIN32_FIND_DATA fdat;
  339. int ok;
  340. if ((last = strrchr(src, '/')) == NULL)
  341. last = src;
  342. else
  343. last++;
  344. if (strrchr(last, '\\') != NULL)
  345. last = strrchr(last, '\\') + 1;
  346. if (last == src && strchr(src, ':') != NULL)
  347. last = strchr(src, ':') + 1;
  348. /* maybe send filetime */
  349. sprintf(buf, "D0755 0 %s\n", last);
  350. if (verbose)
  351. fprintf(stderr, "Entering directory: %s", buf);
  352. ssh_scp_send(buf, strlen(buf));
  353. if (response())
  354. return;
  355. sprintf(buf, "%s/*", src);
  356. dir = FindFirstFile(buf, &fdat);
  357. ok = (dir != INVALID_HANDLE_VALUE);
  358. while (ok) {
  359. if (strcmp(fdat.cFileName, ".") == 0 ||
  360. strcmp(fdat.cFileName, "..") == 0) {
  361. } else if (strlen(src) + 1 + strlen(fdat.cFileName) >=
  362. sizeof(buf)) {
  363. run_err("%s/%s: Name too long", src, fdat.cFileName);
  364. } else {
  365. sprintf(buf, "%s/%s", src, fdat.cFileName);
  366. source(buf);
  367. }
  368. ok = FindNextFile(dir, &fdat);
  369. }
  370. FindClose(dir);
  371. sprintf(buf, "E\n");
  372. ssh_scp_send(buf, strlen(buf));
  373. (void) response();
  374. }
  375. /*
  376. * Execute the sink part of the SCP protocol.
  377. */
  378. static void sink(char *targ)
  379. {
  380. char buf[2048];
  381. char namebuf[2048];
  382. char ch;
  383. int targisdir = 0;
  384. int settime;
  385. int exists;
  386. DWORD attr;
  387. HANDLE f;
  388. unsigned long mtime, atime;
  389. unsigned int mode;
  390. unsigned long size, i;
  391. int wrerror = 0;
  392. unsigned long stat_bytes;
  393. time_t stat_starttime, stat_lasttime;
  394. char *stat_name;
  395. attr = GetFileAttributes(targ);
  396. if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
  397. targisdir = 1;
  398. if (targetshouldbedirectory && !targisdir)
  399. bump("%s: Not a directory", targ);
  400. ssh_scp_send("", 1);
  401. while (1) {
  402. settime = 0;
  403. gottime:
  404. if (ssh_scp_recv(&ch, 1) <= 0)
  405. return;
  406. if (ch == '\n')
  407. bump("Protocol error: Unexpected newline");
  408. i = 0;
  409. buf[i++] = ch;
  410. do {
  411. if (ssh_scp_recv(&ch, 1) <= 0)
  412. bump("Lost connection");
  413. buf[i++] = ch;
  414. } while (i < sizeof(buf) && ch != '\n');
  415. buf[i-1] = '\0';
  416. switch (buf[0]) {
  417. case '\01': /* error */
  418. fprintf(stderr, "%s\n", buf+1);
  419. errs++;
  420. continue;
  421. case '\02': /* fatal error */
  422. bump("%s", buf+1);
  423. case 'E':
  424. ssh_scp_send("", 1);
  425. return;
  426. case 'T':
  427. if (sscanf(buf, "T%ld %*d %ld %*d",
  428. &mtime, &atime) == 2) {
  429. settime = 1;
  430. ssh_scp_send("", 1);
  431. goto gottime;
  432. }
  433. bump("Protocol error: Illegal time format");
  434. case 'C':
  435. case 'D':
  436. break;
  437. default:
  438. bump("Protocol error: Expected control record");
  439. }
  440. if (sscanf(buf+1, "%u %lu %[^\n]", &mode, &size, namebuf) != 3)
  441. bump("Protocol error: Illegal file descriptor format");
  442. if (targisdir) {
  443. char t[2048];
  444. strcpy(t, targ);
  445. if (targ[0] != '\0')
  446. strcat(t, "/");
  447. strcat(t, namebuf);
  448. strcpy(namebuf, t);
  449. } else {
  450. strcpy(namebuf, targ);
  451. }
  452. attr = GetFileAttributes(namebuf);
  453. exists = (attr != (DWORD)-1);
  454. if (buf[0] == 'D') {
  455. if (exists && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  456. run_err("%s: Not a directory", namebuf);
  457. continue;
  458. }
  459. if (!exists) {
  460. if (! CreateDirectory(namebuf, NULL)) {
  461. run_err("%s: Cannot create directory",
  462. namebuf);
  463. continue;
  464. }
  465. }
  466. sink(namebuf);
  467. /* can we set the timestamp for directories ? */
  468. continue;
  469. }
  470. f = CreateFile(namebuf, GENERIC_WRITE, 0, NULL,
  471. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  472. if (f == INVALID_HANDLE_VALUE) {
  473. run_err("%s: Cannot create file", namebuf);
  474. continue;
  475. }
  476. ssh_scp_send("", 1);
  477. if (statistics) {
  478. stat_bytes = 0;
  479. stat_starttime = time(NULL);
  480. stat_lasttime = 0;
  481. if ((stat_name = strrchr(namebuf, '/')) == NULL)
  482. stat_name = namebuf;
  483. else
  484. stat_name++;
  485. if (strrchr(stat_name, '\\') != NULL)
  486. stat_name = strrchr(stat_name, '\\') + 1;
  487. }
  488. for (i = 0; i < size; i += 4096) {
  489. char transbuf[4096];
  490. DWORD j, k = 4096;
  491. if (i + k > size) k = size - i;
  492. if (ssh_scp_recv(transbuf, k) == 0)
  493. bump("Lost connection");
  494. if (wrerror) continue;
  495. if (! WriteFile(f, transbuf, k, &j, NULL) || j != k) {
  496. wrerror = 1;
  497. if (statistics)
  498. printf("\r%-25.25s | %50s\n",
  499. stat_name,
  500. "Write error.. waiting for end of file");
  501. continue;
  502. }
  503. if (statistics) {
  504. stat_bytes += k;
  505. if (time(NULL) > stat_lasttime ||
  506. i + k == size) {
  507. stat_lasttime = time(NULL);
  508. print_stats(stat_name, size, stat_bytes,
  509. stat_starttime, stat_lasttime);
  510. }
  511. }
  512. }
  513. (void) response();
  514. if (settime) {
  515. FILETIME actime, wrtime;
  516. TIME_POSIX_TO_WIN(atime, actime);
  517. TIME_POSIX_TO_WIN(mtime, wrtime);
  518. SetFileTime(f, NULL, &actime, &wrtime);
  519. }
  520. CloseHandle(f);
  521. if (wrerror) {
  522. run_err("%s: Write error", namebuf);
  523. continue;
  524. }
  525. ssh_scp_send("", 1);
  526. }
  527. }
  528. /*
  529. * We will copy local files to a remote server.
  530. */
  531. static void toremote(int argc, char *argv[])
  532. {
  533. char *src, *targ, *host, *user;
  534. char *cmd;
  535. int i;
  536. targ = argv[argc-1];
  537. /* Separate host from filename */
  538. host = targ;
  539. targ = colon(targ);
  540. if (targ == NULL)
  541. bump("targ == NULL in toremote()");
  542. *targ++ = '\0';
  543. if (*targ == '\0')
  544. targ = ".";
  545. /* Substitute "." for emtpy target */
  546. /* Separate host and username */
  547. user = host;
  548. host = strrchr(host, '@');
  549. if (host == NULL) {
  550. host = user;
  551. user = NULL;
  552. } else {
  553. *host++ = '\0';
  554. if (*user == '\0')
  555. user = NULL;
  556. }
  557. if (argc == 2) {
  558. /* Find out if the source filespec covers multiple files
  559. if so, we should set the targetshouldbedirectory flag */
  560. HANDLE fh;
  561. WIN32_FIND_DATA fdat;
  562. if (colon(argv[0]) != NULL)
  563. bump("%s: Remote to remote not supported", argv[0]);
  564. fh = FindFirstFile(argv[0], &fdat);
  565. if (fh == INVALID_HANDLE_VALUE)
  566. bump("%s: No such file or directory\n", argv[0]);
  567. if (FindNextFile(fh, &fdat))
  568. targetshouldbedirectory = 1;
  569. FindClose(fh);
  570. }
  571. cmd = smalloc(strlen(targ) + 100);
  572. sprintf(cmd, "scp%s%s%s%s -t %s",
  573. verbose ? " -v" : "",
  574. recursive ? " -r" : "",
  575. preserve ? " -p" : "",
  576. targetshouldbedirectory ? " -d" : "",
  577. targ);
  578. do_cmd(host, user, cmd);
  579. sfree(cmd);
  580. (void) response();
  581. for (i = 0; i < argc - 1; i++) {
  582. HANDLE dir;
  583. WIN32_FIND_DATA fdat;
  584. src = argv[i];
  585. if (colon(src) != NULL) {
  586. fprintf(stderr,
  587. "%s: Remote to remote not supported\n", src);
  588. errs++;
  589. continue;
  590. }
  591. dir = FindFirstFile(src, &fdat);
  592. if (dir == INVALID_HANDLE_VALUE) {
  593. run_err("%s: No such file or directory", src);
  594. continue;
  595. }
  596. do {
  597. char *last;
  598. char namebuf[2048];
  599. if (strlen(src) + strlen(fdat.cFileName) >=
  600. sizeof(namebuf)) {
  601. fprintf(stderr, "%s: Name too long", src);
  602. continue;
  603. }
  604. strcpy(namebuf, src);
  605. if ((last = strrchr(namebuf, '/')) == NULL)
  606. last = namebuf;
  607. else
  608. last++;
  609. if (strrchr(last, '\\') != NULL)
  610. last = strrchr(last, '\\') + 1;
  611. if (last == namebuf && strrchr(namebuf, ':') != NULL)
  612. last = strchr(namebuf, ':') + 1;
  613. strcpy(last, fdat.cFileName);
  614. source(namebuf);
  615. } while (FindNextFile(dir, &fdat));
  616. FindClose(dir);
  617. }
  618. }
  619. /*
  620. * We will copy files from a remote server to the local machine.
  621. */
  622. static void tolocal(int argc, char *argv[])
  623. {
  624. char *src, *targ, *host, *user;
  625. char *cmd;
  626. if (argc != 2)
  627. bump("More than one remote source not supported");
  628. src = argv[0];
  629. targ = argv[1];
  630. /* Separate host from filename */
  631. host = src;
  632. src = colon(src);
  633. if (src == NULL)
  634. bump("Local to local copy not supported");
  635. *src++ = '\0';
  636. if (*src == '\0')
  637. src = ".";
  638. /* Substitute "." for empty filename */
  639. /* Separate username and hostname */
  640. user = host;
  641. host = strrchr(host, '@');
  642. if (host == NULL) {
  643. host = user;
  644. user = NULL;
  645. } else {
  646. *host++ = '\0';
  647. if (*user == '\0')
  648. user = NULL;
  649. }
  650. cmd = smalloc(strlen(src) + 100);
  651. sprintf(cmd, "scp%s%s%s%s -f %s",
  652. verbose ? " -v" : "",
  653. recursive ? " -r" : "",
  654. preserve ? " -p" : "",
  655. targetshouldbedirectory ? " -d" : "",
  656. src);
  657. do_cmd(host, user, cmd);
  658. sfree(cmd);
  659. sink(targ);
  660. }
  661. /*
  662. * We will issue a list command to get a remote directory.
  663. */
  664. static void get_dir_list(int argc, char *argv[])
  665. {
  666. char *src, *host, *user;
  667. char *cmd, *p, *q;
  668. char c;
  669. src = argv[0];
  670. /* Separate host from filename */
  671. host = src;
  672. src = colon(src);
  673. if (src == NULL)
  674. bump("Local to local copy not supported");
  675. *src++ = '\0';
  676. if (*src == '\0')
  677. src = ".";
  678. /* Substitute "." for empty filename */
  679. /* Separate username and hostname */
  680. user = host;
  681. host = strrchr(host, '@');
  682. if (host == NULL) {
  683. host = user;
  684. user = NULL;
  685. } else {
  686. *host++ = '\0';
  687. if (*user == '\0')
  688. user = NULL;
  689. }
  690. cmd = smalloc(4*strlen(src) + 100);
  691. strcpy(cmd, "ls -la '");
  692. p = cmd + strlen(cmd);
  693. for (q = src; *q; q++) {
  694. if (*q == '\'') {
  695. *p++ = '\''; *p++ = '\\'; *p++ = '\''; *p++ = '\'';
  696. } else {
  697. *p++ = *q;
  698. }
  699. }
  700. *p++ = '\'';
  701. *p = '\0';
  702. do_cmd(host, user, cmd);
  703. sfree(cmd);
  704. while (ssh_scp_recv(&c, 1) > 0)
  705. fputc(c, stdout); /* thank heavens for buffered I/O */
  706. }
  707. /*
  708. * Initialize the Win$ock driver.
  709. */
  710. static void init_winsock(void)
  711. {
  712. WORD winsock_ver;
  713. WSADATA wsadata;
  714. winsock_ver = MAKEWORD(1, 1);
  715. if (WSAStartup(winsock_ver, &wsadata))
  716. bump("Unable to initialise WinSock");
  717. if (LOBYTE(wsadata.wVersion) != 1 ||
  718. HIBYTE(wsadata.wVersion) != 1)
  719. bump("WinSock version is incompatible with 1.1");
  720. }
  721. /*
  722. * Short description of parameters.
  723. */
  724. static void usage(void)
  725. {
  726. printf("PuTTY Secure Copy client\n");
  727. printf("%s\n", ver);
  728. printf("Usage: pscp [options] [user@]host:source target\n");
  729. printf(" pscp [options] source [source...] [user@]host:target\n");
  730. printf(" pscp [options] -ls user@host:filespec\n");
  731. printf("Options:\n");
  732. printf(" -p preserve file attributes\n");
  733. printf(" -q quiet, don't show statistics\n");
  734. printf(" -r copy directories recursively\n");
  735. printf(" -v show verbose messages\n");
  736. printf(" -P port connect to specified port\n");
  737. printf(" -pw passw login with specified password\n");
  738. exit(1);
  739. }
  740. /*
  741. * Main program (no, really?)
  742. */
  743. int main(int argc, char *argv[])
  744. {
  745. int i;
  746. int list = 0;
  747. default_protocol = PROT_TELNET;
  748. scp_flags = SCP_FLAG;
  749. ssh_get_password = &get_password;
  750. init_winsock();
  751. for (i = 1; i < argc; i++) {
  752. if (argv[i][0] != '-')
  753. break;
  754. if (strcmp(argv[i], "-v") == 0)
  755. verbose = 1, scp_flags |= SCP_VERBOSE;
  756. else if (strcmp(argv[i], "-r") == 0)
  757. recursive = 1;
  758. else if (strcmp(argv[i], "-p") == 0)
  759. preserve = 1;
  760. else if (strcmp(argv[i], "-q") == 0)
  761. statistics = 0;
  762. else if (strcmp(argv[i], "-h") == 0 ||
  763. strcmp(argv[i], "-?") == 0)
  764. usage();
  765. else if (strcmp(argv[i], "-P") == 0 && i+1 < argc)
  766. portnumber = atoi(argv[++i]);
  767. else if (strcmp(argv[i], "-pw") == 0 && i+1 < argc)
  768. password = argv[++i];
  769. else if (strcmp(argv[i], "-ls") == 0)
  770. list = 1;
  771. else if (strcmp(argv[i], "--") == 0)
  772. { i++; break; }
  773. else
  774. usage();
  775. }
  776. argc -= i;
  777. argv += i;
  778. if (list) {
  779. if (argc != 1)
  780. usage();
  781. get_dir_list(argc, argv);
  782. } else {
  783. if (argc < 2)
  784. usage();
  785. if (argc > 2)
  786. targetshouldbedirectory = 1;
  787. if (colon(argv[argc-1]) != NULL)
  788. toremote(argc, argv);
  789. else
  790. tolocal(argc, argv);
  791. }
  792. if (connection_open) {
  793. char ch;
  794. ssh_scp_send_eof();
  795. ssh_scp_recv(&ch, 1);
  796. }
  797. WSACleanup();
  798. random_save_seed();
  799. return (errs == 0 ? 0 : 1);
  800. }
  801. /* end */