uxsftp.c 12 KB

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