sftp.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /*
  2. * sftp.c: the Unix-specific parts of PSFTP and PSCP.
  3. */
  4. #include <sys/time.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <stdlib.h>
  8. #include <fcntl.h>
  9. #include <dirent.h>
  10. #include <unistd.h>
  11. #include <utime.h>
  12. #include <errno.h>
  13. #include <assert.h>
  14. #include "putty.h"
  15. #include "ssh.h"
  16. #include "psftp.h"
  17. #if HAVE_GLOB_H
  18. #include <glob.h>
  19. #endif
  20. char *x_get_default(const char *key)
  21. {
  22. return NULL; /* this is a stub */
  23. }
  24. void platform_get_x11_auth(struct X11Display *display, Conf *conf)
  25. {
  26. /* Do nothing, therefore no auth. */
  27. }
  28. const bool platform_uses_x11_unix_by_default = true;
  29. /*
  30. * Default settings that are specific to PSFTP.
  31. */
  32. char *platform_default_s(const char *name)
  33. {
  34. return NULL;
  35. }
  36. bool platform_default_b(const char *name, bool def)
  37. {
  38. return def;
  39. }
  40. int platform_default_i(const char *name, int def)
  41. {
  42. return def;
  43. }
  44. FontSpec *platform_default_fontspec(const char *name)
  45. {
  46. return fontspec_new_default();
  47. }
  48. Filename *platform_default_filename(const char *name)
  49. {
  50. if (!strcmp(name, "LogFileName"))
  51. return filename_from_str("putty.log");
  52. else
  53. return filename_from_str("");
  54. }
  55. SeatPromptResult filexfer_get_userpass_input(Seat *seat, prompts_t *p)
  56. {
  57. /* The file transfer tools don't support Restart Session, so we
  58. * can just have a single static cmdline_get_passwd_input_state
  59. * that's never reset */
  60. static cmdline_get_passwd_input_state cmdline_state =
  61. CMDLINE_GET_PASSWD_INPUT_STATE_INIT;
  62. SeatPromptResult spr;
  63. spr = cmdline_get_passwd_input(p, &cmdline_state, false);
  64. if (spr.kind == SPRK_INCOMPLETE)
  65. spr = console_get_userpass_input(p);
  66. return spr;
  67. }
  68. /*
  69. * Set local current directory. Returns NULL on success, or else an
  70. * error message which must be freed after printing.
  71. */
  72. char *psftp_lcd(char *dir)
  73. {
  74. if (chdir(dir) < 0)
  75. return dupprintf("%s: chdir: %s", dir, strerror(errno));
  76. else
  77. return NULL;
  78. }
  79. /*
  80. * Get local current directory. Returns a string which must be
  81. * freed.
  82. */
  83. char *psftp_getcwd(void)
  84. {
  85. char *buffer, *ret;
  86. size_t size = 256;
  87. buffer = snewn(size, char);
  88. while (1) {
  89. ret = getcwd(buffer, size);
  90. if (ret != NULL)
  91. return ret;
  92. if (errno != ERANGE) {
  93. sfree(buffer);
  94. return dupprintf("[cwd unavailable: %s]", strerror(errno));
  95. }
  96. /*
  97. * Otherwise, ERANGE was returned, meaning the buffer
  98. * wasn't big enough.
  99. */
  100. sgrowarray(buffer, size, size);
  101. }
  102. }
  103. struct RFile {
  104. int fd;
  105. };
  106. RFile *open_existing_file(const char *name, uint64_t *size,
  107. unsigned long *mtime, unsigned long *atime,
  108. long *perms)
  109. {
  110. int fd;
  111. RFile *f;
  112. fd = open(name, O_RDONLY);
  113. if (fd < 0)
  114. return NULL;
  115. f = snew(RFile);
  116. f->fd = fd;
  117. if (size || mtime || atime || perms) {
  118. struct stat statbuf;
  119. if (fstat(fd, &statbuf) < 0) {
  120. fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
  121. memset(&statbuf, 0, sizeof(statbuf));
  122. }
  123. if (size)
  124. *size = statbuf.st_size;
  125. if (mtime)
  126. *mtime = statbuf.st_mtime;
  127. if (atime)
  128. *atime = statbuf.st_atime;
  129. if (perms)
  130. *perms = statbuf.st_mode;
  131. }
  132. return f;
  133. }
  134. int read_from_file(RFile *f, void *buffer, int length)
  135. {
  136. return read(f->fd, buffer, length);
  137. }
  138. void close_rfile(RFile *f)
  139. {
  140. close(f->fd);
  141. sfree(f);
  142. }
  143. struct WFile {
  144. int fd;
  145. char *name;
  146. };
  147. WFile *open_new_file(const char *name, long perms)
  148. {
  149. int fd;
  150. WFile *f;
  151. fd = open(name, O_CREAT | O_TRUNC | O_WRONLY,
  152. (mode_t)(perms ? perms : 0666));
  153. if (fd < 0)
  154. return NULL;
  155. f = snew(WFile);
  156. f->fd = fd;
  157. f->name = dupstr(name);
  158. return f;
  159. }
  160. WFile *open_existing_wfile(const char *name, uint64_t *size)
  161. {
  162. int fd;
  163. WFile *f;
  164. fd = open(name, O_APPEND | O_WRONLY);
  165. if (fd < 0)
  166. return NULL;
  167. f = snew(WFile);
  168. f->fd = fd;
  169. f->name = dupstr(name);
  170. if (size) {
  171. struct stat statbuf;
  172. if (fstat(fd, &statbuf) < 0) {
  173. fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
  174. memset(&statbuf, 0, sizeof(statbuf));
  175. }
  176. *size = statbuf.st_size;
  177. }
  178. return f;
  179. }
  180. int write_to_file(WFile *f, void *buffer, int length)
  181. {
  182. char *p = (char *)buffer;
  183. int so_far = 0;
  184. /* Keep trying until we've really written as much as we can. */
  185. while (length > 0) {
  186. int ret = write(f->fd, p, length);
  187. if (ret < 0)
  188. return ret;
  189. if (ret == 0)
  190. break;
  191. p += ret;
  192. length -= ret;
  193. so_far += ret;
  194. }
  195. return so_far;
  196. }
  197. void set_file_times(WFile *f, unsigned long mtime, unsigned long atime)
  198. {
  199. struct utimbuf ut;
  200. ut.actime = atime;
  201. ut.modtime = mtime;
  202. utime(f->name, &ut);
  203. }
  204. /* Closes and frees the WFile */
  205. void close_wfile(WFile *f)
  206. {
  207. close(f->fd);
  208. sfree(f->name);
  209. sfree(f);
  210. }
  211. /* Seek offset bytes through file, from whence, where whence is
  212. FROM_START, FROM_CURRENT, or FROM_END */
  213. int seek_file(WFile *f, uint64_t offset, int whence)
  214. {
  215. int lseek_whence;
  216. switch (whence) {
  217. case FROM_START:
  218. lseek_whence = SEEK_SET;
  219. break;
  220. case FROM_CURRENT:
  221. lseek_whence = SEEK_CUR;
  222. break;
  223. case FROM_END:
  224. lseek_whence = SEEK_END;
  225. break;
  226. default:
  227. return -1;
  228. }
  229. return lseek(f->fd, offset, lseek_whence) >= 0 ? 0 : -1;
  230. }
  231. uint64_t get_file_posn(WFile *f)
  232. {
  233. return lseek(f->fd, (off_t) 0, SEEK_CUR);
  234. }
  235. int file_type(const char *name)
  236. {
  237. struct stat statbuf;
  238. if (stat(name, &statbuf) < 0) {
  239. if (errno != ENOENT)
  240. fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
  241. return FILE_TYPE_NONEXISTENT;
  242. }
  243. if (S_ISREG(statbuf.st_mode))
  244. return FILE_TYPE_FILE;
  245. if (S_ISDIR(statbuf.st_mode))
  246. return FILE_TYPE_DIRECTORY;
  247. return FILE_TYPE_WEIRD;
  248. }
  249. struct DirHandle {
  250. DIR *dir;
  251. };
  252. DirHandle *open_directory(const char *name, const char **errmsg)
  253. {
  254. DIR *dp = opendir(name);
  255. if (!dp) {
  256. *errmsg = strerror(errno);
  257. return NULL;
  258. }
  259. DirHandle *dir = snew(DirHandle);
  260. dir->dir = dp;
  261. return dir;
  262. }
  263. char *read_filename(DirHandle *dir)
  264. {
  265. struct dirent *de;
  266. do {
  267. de = readdir(dir->dir);
  268. if (de == NULL)
  269. return NULL;
  270. } while ((de->d_name[0] == '.' &&
  271. (de->d_name[1] == '\0' ||
  272. (de->d_name[1] == '.' && de->d_name[2] == '\0'))));
  273. return dupstr(de->d_name);
  274. }
  275. void close_directory(DirHandle *dir)
  276. {
  277. closedir(dir->dir);
  278. sfree(dir);
  279. }
  280. int test_wildcard(const char *name, bool cmdline)
  281. {
  282. struct stat statbuf;
  283. if (stat(name, &statbuf) == 0) {
  284. return WCTYPE_FILENAME;
  285. } else if (cmdline) {
  286. /*
  287. * On Unix, we never need to parse wildcards coming from
  288. * the command line, because the shell will have expanded
  289. * them into a filename list already.
  290. */
  291. return WCTYPE_NONEXISTENT;
  292. } else {
  293. #if HAVE_GLOB_H
  294. glob_t globbed;
  295. int ret = WCTYPE_NONEXISTENT;
  296. if (glob(name, GLOB_ERR, NULL, &globbed) == 0) {
  297. if (globbed.gl_pathc > 0)
  298. ret = WCTYPE_WILDCARD;
  299. globfree(&globbed);
  300. }
  301. return ret;
  302. #else
  303. /* On a system without glob.h, we just have to return a
  304. * failure code */
  305. return WCTYPE_NONEXISTENT;
  306. #endif
  307. }
  308. }
  309. /*
  310. * Actually return matching file names for a local wildcard.
  311. */
  312. #if HAVE_GLOB_H
  313. struct WildcardMatcher {
  314. glob_t globbed;
  315. int i;
  316. };
  317. WildcardMatcher *begin_wildcard_matching(const char *name) {
  318. WildcardMatcher *dir = snew(WildcardMatcher);
  319. if (glob(name, 0, NULL, &dir->globbed) < 0) {
  320. sfree(dir);
  321. return NULL;
  322. }
  323. dir->i = 0;
  324. return dir;
  325. }
  326. char *wildcard_get_filename(WildcardMatcher *dir) {
  327. if (dir->i < dir->globbed.gl_pathc) {
  328. return dupstr(dir->globbed.gl_pathv[dir->i++]);
  329. } else
  330. return NULL;
  331. }
  332. void finish_wildcard_matching(WildcardMatcher *dir) {
  333. globfree(&dir->globbed);
  334. sfree(dir);
  335. }
  336. #else
  337. WildcardMatcher *begin_wildcard_matching(const char *name)
  338. {
  339. return NULL;
  340. }
  341. char *wildcard_get_filename(WildcardMatcher *dir)
  342. {
  343. unreachable("Can't construct a valid WildcardMatcher without <glob.h>");
  344. }
  345. void finish_wildcard_matching(WildcardMatcher *dir)
  346. {
  347. unreachable("Can't construct a valid WildcardMatcher without <glob.h>");
  348. }
  349. #endif
  350. char *stripslashes(const char *str, bool local)
  351. {
  352. char *p;
  353. /*
  354. * On Unix, we do the same thing regardless of the 'local'
  355. * parameter.
  356. */
  357. p = strrchr(str, '/');
  358. if (p) str = p+1;
  359. return (char *)str;
  360. }
  361. bool vet_filename(const char *name)
  362. {
  363. if (strchr(name, '/'))
  364. return false;
  365. if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
  366. return false;
  367. return true;
  368. }
  369. bool create_directory(const char *name)
  370. {
  371. return mkdir(name, 0777) == 0;
  372. }
  373. char *dir_file_cat(const char *dir, const char *file)
  374. {
  375. ptrlen dir_pl = ptrlen_from_asciz(dir);
  376. return dupcat(
  377. dir, ptrlen_endswith(dir_pl, PTRLEN_LITERAL("/"), NULL) ? "" : "/",
  378. file);
  379. }
  380. /*
  381. * Do a select() between all currently active network fds and
  382. * optionally stdin, using cli_main_loop.
  383. */
  384. struct ssh_sftp_mainloop_ctx {
  385. bool include_stdin, no_fds_ok;
  386. int toret;
  387. };
  388. static bool ssh_sftp_pw_setup(void *vctx, pollwrapper *pw)
  389. {
  390. struct ssh_sftp_mainloop_ctx *ctx = (struct ssh_sftp_mainloop_ctx *)vctx;
  391. int fdstate, rwx;
  392. if (!ctx->no_fds_ok && !toplevel_callback_pending() &&
  393. first_fd(&fdstate, &rwx) < 0) {
  394. ctx->toret = -1;
  395. return false; /* terminate cli_main_loop */
  396. }
  397. if (ctx->include_stdin)
  398. pollwrap_add_fd_rwx(pw, 0, SELECT_R);
  399. return true;
  400. }
  401. static void ssh_sftp_pw_check(void *vctx, pollwrapper *pw)
  402. {
  403. struct ssh_sftp_mainloop_ctx *ctx = (struct ssh_sftp_mainloop_ctx *)vctx;
  404. if (ctx->include_stdin && pollwrap_check_fd_rwx(pw, 0, SELECT_R))
  405. ctx->toret = 1;
  406. }
  407. static bool ssh_sftp_mainloop_continue(void *vctx, bool found_any_fd,
  408. bool ran_any_callback)
  409. {
  410. struct ssh_sftp_mainloop_ctx *ctx = (struct ssh_sftp_mainloop_ctx *)vctx;
  411. if (ctx->toret != 0 || found_any_fd || ran_any_callback)
  412. return false; /* finish the loop */
  413. return true;
  414. }
  415. static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
  416. {
  417. struct ssh_sftp_mainloop_ctx ctx[1];
  418. ctx->include_stdin = include_stdin;
  419. ctx->no_fds_ok = no_fds_ok;
  420. ctx->toret = 0;
  421. cli_main_loop(ssh_sftp_pw_setup, ssh_sftp_pw_check,
  422. ssh_sftp_mainloop_continue, ctx);
  423. return ctx->toret;
  424. }
  425. /*
  426. * Wait for some network data and process it.
  427. */
  428. int ssh_sftp_loop_iteration(void)
  429. {
  430. return ssh_sftp_do_select(false, false);
  431. }
  432. /*
  433. * Read a PSFTP command line from stdin.
  434. */
  435. char *ssh_sftp_get_cmdline(const char *prompt, bool no_fds_ok)
  436. {
  437. char *buf;
  438. size_t buflen, bufsize;
  439. int ret;
  440. fputs(prompt, stdout);
  441. fflush(stdout);
  442. buf = NULL;
  443. buflen = bufsize = 0;
  444. while (1) {
  445. ret = ssh_sftp_do_select(true, no_fds_ok);
  446. if (ret < 0) {
  447. printf("connection died\n");
  448. sfree(buf);
  449. return NULL; /* woop woop */
  450. }
  451. if (ret > 0) {
  452. sgrowarray(buf, bufsize, buflen);
  453. ret = read(0, buf+buflen, 1);
  454. if (ret < 0) {
  455. perror("read");
  456. sfree(buf);
  457. return NULL;
  458. }
  459. if (ret == 0) {
  460. /* eof on stdin; no error, but no answer either */
  461. sfree(buf);
  462. return NULL;
  463. }
  464. if (buf[buflen++] == '\n') {
  465. /* we have a full line */
  466. return buf;
  467. }
  468. }
  469. }
  470. }
  471. void frontend_net_error_pending(void) {}
  472. void platform_psftp_pre_conn_setup(LogPolicy *lp) {}
  473. const bool buildinfo_gtk_relevant = false;
  474. /*
  475. * Main program: do platform-specific initialisation and then call
  476. * psftp_main().
  477. */
  478. int main(int argc, char *argv[])
  479. {
  480. uxsel_init();
  481. return psftp_main(argc, argv);
  482. }