postlogin.c 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019
  1. /*
  2. * Part of Very Secure FTPd
  3. * Licence: GPL v2
  4. * Author: Chris Evans
  5. * postlogin.c
  6. */
  7. #include "postlogin.h"
  8. #include "session.h"
  9. #include "oneprocess.h"
  10. #include "twoprocess.h"
  11. #include "ftpcodes.h"
  12. #include "ftpcmdio.h"
  13. #include "ftpdataio.h"
  14. #include "utility.h"
  15. #include "tunables.h"
  16. #include "defs.h"
  17. #include "str.h"
  18. #include "sysstr.h"
  19. #include "banner.h"
  20. #include "sysutil.h"
  21. #include "logging.h"
  22. #include "sysdeputil.h"
  23. #include "ipaddrparse.h"
  24. #include "access.h"
  25. #include "features.h"
  26. #include "ssl.h"
  27. #include "vsftpver.h"
  28. #include "opts.h"
  29. /* Private local functions */
  30. static void handle_pwd(struct vsf_session* p_sess);
  31. static void handle_cwd(struct vsf_session* p_sess);
  32. static void handle_pasv(struct vsf_session* p_sess, int is_epsv);
  33. static void handle_retr(struct vsf_session* p_sess, int is_http);
  34. static void handle_cdup(struct vsf_session* p_sess);
  35. static void handle_list(struct vsf_session* p_sess);
  36. static void handle_type(struct vsf_session* p_sess);
  37. static void handle_port(struct vsf_session* p_sess);
  38. static void handle_stor(struct vsf_session* p_sess);
  39. static void handle_mkd(struct vsf_session* p_sess);
  40. static void handle_rmd(struct vsf_session* p_sess);
  41. static void handle_dele(struct vsf_session* p_sess);
  42. static void handle_rest(struct vsf_session* p_sess);
  43. static void handle_rnfr(struct vsf_session* p_sess);
  44. static void handle_rnto(struct vsf_session* p_sess);
  45. static void handle_nlst(struct vsf_session* p_sess);
  46. static void handle_size(struct vsf_session* p_sess);
  47. static void handle_site(struct vsf_session* p_sess);
  48. static void handle_appe(struct vsf_session* p_sess);
  49. static void handle_mdtm(struct vsf_session* p_sess);
  50. static void handle_site_chmod(struct vsf_session* p_sess,
  51. struct mystr* p_arg_str);
  52. static void handle_site_umask(struct vsf_session* p_sess,
  53. struct mystr* p_arg_str);
  54. static void handle_eprt(struct vsf_session* p_sess);
  55. static void handle_help(struct vsf_session* p_sess);
  56. static void handle_stou(struct vsf_session* p_sess);
  57. static void handle_stat(struct vsf_session* p_sess);
  58. static void handle_stat_file(struct vsf_session* p_sess);
  59. static void handle_logged_in_user(struct vsf_session* p_sess);
  60. static void handle_logged_in_pass(struct vsf_session* p_sess);
  61. static void handle_http(struct vsf_session* p_sess);
  62. static int pasv_active(struct vsf_session* p_sess);
  63. static int port_active(struct vsf_session* p_sess);
  64. static void pasv_cleanup(struct vsf_session* p_sess);
  65. static void port_cleanup(struct vsf_session* p_sess);
  66. static void handle_dir_common(struct vsf_session* p_sess, int full_details,
  67. int stat_cmd);
  68. static void prepend_path_to_filename(struct mystr* p_str);
  69. static int get_remote_transfer_fd(struct vsf_session* p_sess,
  70. const char* p_status_msg);
  71. static void check_abor(struct vsf_session* p_sess);
  72. static void handle_sigurg(void* p_private);
  73. static void handle_upload_common(struct vsf_session* p_sess, int is_append,
  74. int is_unique);
  75. static void get_unique_filename(struct mystr* p_outstr,
  76. const struct mystr* p_base);
  77. static int data_transfer_checks_ok(struct vsf_session* p_sess);
  78. static void resolve_tilde(struct mystr* p_str, struct vsf_session* p_sess);
  79. void
  80. process_post_login(struct vsf_session* p_sess)
  81. {
  82. str_getcwd(&p_sess->home_str);
  83. if (p_sess->is_anonymous)
  84. {
  85. vsf_sysutil_set_umask(tunable_anon_umask);
  86. p_sess->bw_rate_max = tunable_anon_max_rate;
  87. }
  88. else
  89. {
  90. vsf_sysutil_set_umask(tunable_local_umask);
  91. p_sess->bw_rate_max = tunable_local_max_rate;
  92. }
  93. if (p_sess->is_http)
  94. {
  95. handle_http(p_sess);
  96. bug("should not be reached");
  97. }
  98. /* Don't support async ABOR if we have an SSL channel. The spec says SHOULD
  99. * NOT, and I think there are synchronization issues between command and
  100. * data reads.
  101. */
  102. if (tunable_async_abor_enable && !p_sess->control_use_ssl)
  103. {
  104. vsf_sysutil_install_sighandler(kVSFSysUtilSigURG, handle_sigurg, p_sess, 0);
  105. vsf_sysutil_activate_sigurg(VSFTP_COMMAND_FD);
  106. }
  107. /* Handle any login message */
  108. vsf_banner_dir_changed(p_sess, FTP_LOGINOK);
  109. vsf_cmdio_write(p_sess, FTP_LOGINOK, "Login successful.");
  110. while(1)
  111. {
  112. int cmd_ok = 1;
  113. if (tunable_setproctitle_enable)
  114. {
  115. vsf_sysutil_setproctitle("IDLE");
  116. }
  117. /* Blocks */
  118. vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str,
  119. &p_sess->ftp_arg_str, 1);
  120. if (tunable_setproctitle_enable)
  121. {
  122. struct mystr proctitle_str = INIT_MYSTR;
  123. str_copy(&proctitle_str, &p_sess->ftp_cmd_str);
  124. if (!str_isempty(&p_sess->ftp_arg_str))
  125. {
  126. str_append_char(&proctitle_str, ' ');
  127. str_append_str(&proctitle_str, &p_sess->ftp_arg_str);
  128. }
  129. /* Suggestion from Solar */
  130. str_replace_unprintable(&proctitle_str, '?');
  131. vsf_sysutil_setproctitle_str(&proctitle_str);
  132. str_free(&proctitle_str);
  133. }
  134. /* Test command against the allowed lists.. */
  135. if (tunable_cmds_allowed)
  136. {
  137. static struct mystr s_src_str;
  138. static struct mystr s_rhs_str;
  139. str_alloc_text(&s_src_str, tunable_cmds_allowed);
  140. while (1)
  141. {
  142. str_split_char(&s_src_str, &s_rhs_str, ',');
  143. if (str_isempty(&s_src_str))
  144. {
  145. cmd_ok = 0;
  146. break;
  147. }
  148. else if (str_equal(&s_src_str, &p_sess->ftp_cmd_str))
  149. {
  150. break;
  151. }
  152. str_copy(&s_src_str, &s_rhs_str);
  153. }
  154. }
  155. if (tunable_cmds_denied)
  156. {
  157. static struct mystr s_src_str;
  158. static struct mystr s_rhs_str;
  159. str_alloc_text(&s_src_str, tunable_cmds_denied);
  160. while (1)
  161. {
  162. str_split_char(&s_src_str, &s_rhs_str, ',');
  163. if (str_isempty(&s_src_str))
  164. {
  165. break;
  166. }
  167. else if (str_equal(&s_src_str, &p_sess->ftp_cmd_str))
  168. {
  169. cmd_ok = 0;
  170. break;
  171. }
  172. str_copy(&s_src_str, &s_rhs_str);
  173. }
  174. }
  175. if (!cmd_ok)
  176. {
  177. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  178. }
  179. else if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT"))
  180. {
  181. vsf_cmdio_write_exit(p_sess, FTP_GOODBYE, "Goodbye.", 0);
  182. }
  183. else if (str_equal_text(&p_sess->ftp_cmd_str, "PWD") ||
  184. str_equal_text(&p_sess->ftp_cmd_str, "XPWD"))
  185. {
  186. handle_pwd(p_sess);
  187. }
  188. else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") ||
  189. str_equal_text(&p_sess->ftp_cmd_str, "XCWD"))
  190. {
  191. handle_cwd(p_sess);
  192. }
  193. else if (str_equal_text(&p_sess->ftp_cmd_str, "CDUP") ||
  194. str_equal_text(&p_sess->ftp_cmd_str, "XCUP"))
  195. {
  196. handle_cdup(p_sess);
  197. }
  198. else if (tunable_pasv_enable &&
  199. !p_sess->epsv_all &&
  200. (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
  201. str_equal_text(&p_sess->ftp_cmd_str, "P@SW")))
  202. {
  203. handle_pasv(p_sess, 0);
  204. }
  205. else if (tunable_pasv_enable &&
  206. str_equal_text(&p_sess->ftp_cmd_str, "EPSV"))
  207. {
  208. handle_pasv(p_sess, 1);
  209. }
  210. else if (tunable_download_enable &&
  211. str_equal_text(&p_sess->ftp_cmd_str, "RETR"))
  212. {
  213. handle_retr(p_sess, 0);
  214. }
  215. else if (str_equal_text(&p_sess->ftp_cmd_str, "NOOP"))
  216. {
  217. vsf_cmdio_write(p_sess, FTP_NOOPOK, "NOOP ok.");
  218. }
  219. else if (str_equal_text(&p_sess->ftp_cmd_str, "SYST"))
  220. {
  221. vsf_cmdio_write(p_sess, FTP_SYSTOK, "UNIX Type: L8");
  222. }
  223. else if (str_equal_text(&p_sess->ftp_cmd_str, "HELP"))
  224. {
  225. handle_help(p_sess);
  226. }
  227. else if (tunable_dirlist_enable &&
  228. str_equal_text(&p_sess->ftp_cmd_str, "LIST"))
  229. {
  230. handle_list(p_sess);
  231. }
  232. else if (str_equal_text(&p_sess->ftp_cmd_str, "TYPE"))
  233. {
  234. handle_type(p_sess);
  235. }
  236. else if (tunable_port_enable &&
  237. !p_sess->epsv_all &&
  238. str_equal_text(&p_sess->ftp_cmd_str, "PORT"))
  239. {
  240. handle_port(p_sess);
  241. }
  242. else if (tunable_write_enable &&
  243. (tunable_anon_upload_enable || !p_sess->is_anonymous) &&
  244. str_equal_text(&p_sess->ftp_cmd_str, "STOR"))
  245. {
  246. handle_stor(p_sess);
  247. }
  248. else if (tunable_write_enable &&
  249. (tunable_anon_mkdir_write_enable || !p_sess->is_anonymous) &&
  250. (str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
  251. str_equal_text(&p_sess->ftp_cmd_str, "XMKD")))
  252. {
  253. handle_mkd(p_sess);
  254. }
  255. else if (tunable_write_enable &&
  256. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  257. (str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
  258. str_equal_text(&p_sess->ftp_cmd_str, "XRMD")))
  259. {
  260. handle_rmd(p_sess);
  261. }
  262. else if (tunable_write_enable &&
  263. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  264. str_equal_text(&p_sess->ftp_cmd_str, "DELE"))
  265. {
  266. handle_dele(p_sess);
  267. }
  268. else if (str_equal_text(&p_sess->ftp_cmd_str, "REST"))
  269. {
  270. handle_rest(p_sess);
  271. }
  272. else if (tunable_write_enable &&
  273. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  274. str_equal_text(&p_sess->ftp_cmd_str, "RNFR"))
  275. {
  276. handle_rnfr(p_sess);
  277. }
  278. else if (tunable_write_enable &&
  279. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  280. str_equal_text(&p_sess->ftp_cmd_str, "RNTO"))
  281. {
  282. handle_rnto(p_sess);
  283. }
  284. else if (tunable_dirlist_enable &&
  285. str_equal_text(&p_sess->ftp_cmd_str, "NLST"))
  286. {
  287. handle_nlst(p_sess);
  288. }
  289. else if (str_equal_text(&p_sess->ftp_cmd_str, "SIZE"))
  290. {
  291. handle_size(p_sess);
  292. }
  293. else if (!p_sess->is_anonymous &&
  294. str_equal_text(&p_sess->ftp_cmd_str, "SITE"))
  295. {
  296. handle_site(p_sess);
  297. }
  298. /* Note - the weird ABOR string is checking for an async ABOR arriving
  299. * without a SIGURG condition.
  300. */
  301. else if (str_equal_text(&p_sess->ftp_cmd_str, "ABOR") ||
  302. str_equal_text(&p_sess->ftp_cmd_str, "\377\364\377\362ABOR"))
  303. {
  304. vsf_cmdio_write(p_sess, FTP_ABOR_NOCONN, "No transfer to ABOR.");
  305. }
  306. else if (tunable_write_enable &&
  307. (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
  308. str_equal_text(&p_sess->ftp_cmd_str, "APPE"))
  309. {
  310. handle_appe(p_sess);
  311. }
  312. else if (str_equal_text(&p_sess->ftp_cmd_str, "MDTM"))
  313. {
  314. handle_mdtm(p_sess);
  315. }
  316. else if (tunable_port_enable &&
  317. str_equal_text(&p_sess->ftp_cmd_str, "EPRT"))
  318. {
  319. handle_eprt(p_sess);
  320. }
  321. else if (str_equal_text(&p_sess->ftp_cmd_str, "STRU"))
  322. {
  323. str_upper(&p_sess->ftp_arg_str);
  324. if (str_equal_text(&p_sess->ftp_arg_str, "F"))
  325. {
  326. vsf_cmdio_write(p_sess, FTP_STRUOK, "Structure set to F.");
  327. }
  328. else
  329. {
  330. vsf_cmdio_write(p_sess, FTP_BADSTRU, "Bad STRU command.");
  331. }
  332. }
  333. else if (str_equal_text(&p_sess->ftp_cmd_str, "MODE"))
  334. {
  335. str_upper(&p_sess->ftp_arg_str);
  336. if (str_equal_text(&p_sess->ftp_arg_str, "S"))
  337. {
  338. vsf_cmdio_write(p_sess, FTP_MODEOK, "Mode set to S.");
  339. }
  340. else
  341. {
  342. vsf_cmdio_write(p_sess, FTP_BADMODE, "Bad MODE command.");
  343. }
  344. }
  345. else if (tunable_write_enable &&
  346. (tunable_anon_upload_enable || !p_sess->is_anonymous) &&
  347. str_equal_text(&p_sess->ftp_cmd_str, "STOU"))
  348. {
  349. handle_stou(p_sess);
  350. }
  351. else if (str_equal_text(&p_sess->ftp_cmd_str, "ALLO"))
  352. {
  353. vsf_cmdio_write(p_sess, FTP_ALLOOK, "ALLO command ignored.");
  354. }
  355. else if (str_equal_text(&p_sess->ftp_cmd_str, "REIN"))
  356. {
  357. vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "REIN not implemented.");
  358. }
  359. else if (str_equal_text(&p_sess->ftp_cmd_str, "ACCT"))
  360. {
  361. vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "ACCT not implemented.");
  362. }
  363. else if (str_equal_text(&p_sess->ftp_cmd_str, "SMNT"))
  364. {
  365. vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "SMNT not implemented.");
  366. }
  367. else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT"))
  368. {
  369. handle_feat(p_sess);
  370. }
  371. else if (str_equal_text(&p_sess->ftp_cmd_str, "OPTS"))
  372. {
  373. handle_opts(p_sess);
  374. }
  375. else if (str_equal_text(&p_sess->ftp_cmd_str, "STAT") &&
  376. str_isempty(&p_sess->ftp_arg_str))
  377. {
  378. handle_stat(p_sess);
  379. }
  380. else if (tunable_dirlist_enable &&
  381. str_equal_text(&p_sess->ftp_cmd_str, "STAT"))
  382. {
  383. handle_stat_file(p_sess);
  384. }
  385. else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PBSZ"))
  386. {
  387. handle_pbsz(p_sess);
  388. }
  389. else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
  390. {
  391. handle_prot(p_sess);
  392. }
  393. else if (str_equal_text(&p_sess->ftp_cmd_str, "USER"))
  394. {
  395. handle_logged_in_user(p_sess);
  396. }
  397. else if (str_equal_text(&p_sess->ftp_cmd_str, "PASS"))
  398. {
  399. handle_logged_in_pass(p_sess);
  400. }
  401. else if (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
  402. str_equal_text(&p_sess->ftp_cmd_str, "PORT") ||
  403. str_equal_text(&p_sess->ftp_cmd_str, "STOR") ||
  404. str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
  405. str_equal_text(&p_sess->ftp_cmd_str, "XMKD") ||
  406. str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
  407. str_equal_text(&p_sess->ftp_cmd_str, "XRMD") ||
  408. str_equal_text(&p_sess->ftp_cmd_str, "DELE") ||
  409. str_equal_text(&p_sess->ftp_cmd_str, "RNFR") ||
  410. str_equal_text(&p_sess->ftp_cmd_str, "RNTO") ||
  411. str_equal_text(&p_sess->ftp_cmd_str, "SITE") ||
  412. str_equal_text(&p_sess->ftp_cmd_str, "APPE") ||
  413. str_equal_text(&p_sess->ftp_cmd_str, "EPSV") ||
  414. str_equal_text(&p_sess->ftp_cmd_str, "EPRT") ||
  415. str_equal_text(&p_sess->ftp_cmd_str, "RETR") ||
  416. str_equal_text(&p_sess->ftp_cmd_str, "LIST") ||
  417. str_equal_text(&p_sess->ftp_cmd_str, "NLST") ||
  418. str_equal_text(&p_sess->ftp_cmd_str, "STOU") ||
  419. str_equal_text(&p_sess->ftp_cmd_str, "ALLO") ||
  420. str_equal_text(&p_sess->ftp_cmd_str, "REIN") ||
  421. str_equal_text(&p_sess->ftp_cmd_str, "ACCT") ||
  422. str_equal_text(&p_sess->ftp_cmd_str, "SMNT") ||
  423. str_equal_text(&p_sess->ftp_cmd_str, "FEAT") ||
  424. str_equal_text(&p_sess->ftp_cmd_str, "OPTS") ||
  425. str_equal_text(&p_sess->ftp_cmd_str, "STAT") ||
  426. str_equal_text(&p_sess->ftp_cmd_str, "PBSZ") ||
  427. str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
  428. {
  429. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  430. }
  431. else if (str_isempty(&p_sess->ftp_cmd_str) &&
  432. str_isempty(&p_sess->ftp_arg_str))
  433. {
  434. /* Deliberately ignore to avoid NAT device bugs. ProFTPd does the same. */
  435. }
  436. else if (str_equal_text(&p_sess->ftp_cmd_str, "GET") ||
  437. str_equal_text(&p_sess->ftp_cmd_str, "POST") ||
  438. str_equal_text(&p_sess->ftp_cmd_str, "HEAD") ||
  439. str_equal_text(&p_sess->ftp_cmd_str, "OPTIONS") ||
  440. str_equal_text(&p_sess->ftp_cmd_str, "CONNECT"))
  441. {
  442. vsf_cmdio_write_exit(p_sess, FTP_BADCMD,
  443. "HTTP protocol commands not allowed.", 1);
  444. }
  445. else
  446. {
  447. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
  448. }
  449. if (vsf_log_entry_pending(p_sess))
  450. {
  451. vsf_log_do_log(p_sess, 0);
  452. }
  453. if (p_sess->data_timeout)
  454. {
  455. vsf_cmdio_write_exit(p_sess, FTP_DATA_TIMEOUT,
  456. "Data timeout. Reconnect. Sorry.", 1);
  457. }
  458. }
  459. }
  460. static void
  461. handle_pwd(struct vsf_session* p_sess)
  462. {
  463. static struct mystr s_cwd_buf_mangle_str;
  464. static struct mystr s_pwd_res_str;
  465. str_getcwd(&s_cwd_buf_mangle_str);
  466. /* Double up any double-quotes in the pathname! */
  467. str_replace_text(&s_cwd_buf_mangle_str, "\"", "\"\"");
  468. /* Enclose pathname in quotes */
  469. str_alloc_text(&s_pwd_res_str, "\"");
  470. str_append_str(&s_pwd_res_str, &s_cwd_buf_mangle_str);
  471. str_append_text(&s_pwd_res_str, "\" is the current directory");
  472. vsf_cmdio_write_str(p_sess, FTP_PWDOK, &s_pwd_res_str);
  473. }
  474. static void
  475. handle_cwd(struct vsf_session* p_sess)
  476. {
  477. int retval;
  478. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  479. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  480. {
  481. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  482. return;
  483. }
  484. retval = str_chdir(&p_sess->ftp_arg_str);
  485. if (retval == 0)
  486. {
  487. /* Handle any messages */
  488. vsf_banner_dir_changed(p_sess, FTP_CWDOK);
  489. vsf_cmdio_write(p_sess, FTP_CWDOK, "Directory successfully changed.");
  490. }
  491. else
  492. {
  493. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to change directory.");
  494. }
  495. }
  496. static void
  497. handle_cdup(struct vsf_session* p_sess)
  498. {
  499. str_alloc_text(&p_sess->ftp_arg_str, "..");
  500. handle_cwd(p_sess);
  501. }
  502. static int
  503. port_active(struct vsf_session* p_sess)
  504. {
  505. int ret = 0;
  506. if (p_sess->p_port_sockaddr != 0)
  507. {
  508. ret = 1;
  509. if (pasv_active(p_sess))
  510. {
  511. bug("port and pasv both active");
  512. }
  513. }
  514. return ret;
  515. }
  516. static int
  517. pasv_active(struct vsf_session* p_sess)
  518. {
  519. int ret = 0;
  520. if (tunable_one_process_model)
  521. {
  522. ret = vsf_one_process_pasv_active(p_sess);
  523. }
  524. else
  525. {
  526. ret = vsf_two_process_pasv_active(p_sess);
  527. }
  528. if (ret)
  529. {
  530. if (port_active(p_sess))
  531. {
  532. bug("pasv and port both active");
  533. }
  534. }
  535. return ret;
  536. }
  537. static void
  538. port_cleanup(struct vsf_session* p_sess)
  539. {
  540. vsf_sysutil_sockaddr_clear(&p_sess->p_port_sockaddr);
  541. }
  542. static void
  543. pasv_cleanup(struct vsf_session* p_sess)
  544. {
  545. if (tunable_one_process_model)
  546. {
  547. vsf_one_process_pasv_cleanup(p_sess);
  548. }
  549. else
  550. {
  551. vsf_two_process_pasv_cleanup(p_sess);
  552. }
  553. }
  554. static void
  555. handle_pasv(struct vsf_session* p_sess, int is_epsv)
  556. {
  557. unsigned short the_port;
  558. static struct mystr s_pasv_res_str;
  559. static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  560. int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  561. if (is_epsv && !str_isempty(&p_sess->ftp_arg_str))
  562. {
  563. int argval;
  564. str_upper(&p_sess->ftp_arg_str);
  565. if (str_equal_text(&p_sess->ftp_arg_str, "ALL"))
  566. {
  567. p_sess->epsv_all = 1;
  568. vsf_cmdio_write(p_sess, FTP_EPSVALLOK, "EPSV ALL ok.");
  569. return;
  570. }
  571. argval = vsf_sysutil_atoi(str_getbuf(&p_sess->ftp_arg_str));
  572. if (argval < 1 || argval > 2 || (!is_ipv6 && argval == 2))
  573. {
  574. vsf_cmdio_write(p_sess, FTP_EPSVBAD, "Bad network protocol.");
  575. return;
  576. }
  577. }
  578. pasv_cleanup(p_sess);
  579. port_cleanup(p_sess);
  580. if (tunable_one_process_model)
  581. {
  582. the_port = vsf_one_process_listen(p_sess);
  583. }
  584. else
  585. {
  586. the_port = vsf_two_process_listen(p_sess);
  587. }
  588. if (is_epsv)
  589. {
  590. str_alloc_text(&s_pasv_res_str, "Entering Extended Passive Mode (|||");
  591. str_append_ulong(&s_pasv_res_str, (unsigned long) the_port);
  592. str_append_text(&s_pasv_res_str, "|)");
  593. vsf_cmdio_write_str(p_sess, FTP_EPSVOK, &s_pasv_res_str);
  594. return;
  595. }
  596. if (tunable_pasv_address != 0)
  597. {
  598. vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);
  599. /* Report passive address as specified in configuration */
  600. if (vsf_sysutil_inet_aton(tunable_pasv_address, s_p_sockaddr) == 0)
  601. {
  602. die("invalid pasv_address");
  603. }
  604. }
  605. else
  606. {
  607. vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
  608. }
  609. str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
  610. if (!is_ipv6)
  611. {
  612. str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr));
  613. }
  614. else
  615. {
  616. const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr);
  617. if (p_v4addr)
  618. {
  619. str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr));
  620. }
  621. else
  622. {
  623. str_append_text(&s_pasv_res_str, "0,0,0,0");
  624. }
  625. }
  626. str_replace_char(&s_pasv_res_str, '.', ',');
  627. str_append_text(&s_pasv_res_str, ",");
  628. str_append_ulong(&s_pasv_res_str, the_port >> 8);
  629. str_append_text(&s_pasv_res_str, ",");
  630. str_append_ulong(&s_pasv_res_str, the_port & 255);
  631. str_append_text(&s_pasv_res_str, ").");
  632. vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str);
  633. }
  634. static void
  635. handle_retr(struct vsf_session* p_sess, int is_http)
  636. {
  637. static struct mystr s_mark_str;
  638. static struct vsf_sysutil_statbuf* s_p_statbuf;
  639. struct vsf_transfer_ret trans_ret;
  640. int remote_fd;
  641. int opened_file;
  642. int is_ascii = 0;
  643. filesize_t offset = p_sess->restart_pos;
  644. p_sess->restart_pos = 0;
  645. if (!is_http && !data_transfer_checks_ok(p_sess))
  646. {
  647. return;
  648. }
  649. if (p_sess->is_ascii && offset != 0)
  650. {
  651. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  652. "No support for resume of ASCII transfer.");
  653. return;
  654. }
  655. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  656. vsf_log_start_entry(p_sess, kVSFLogEntryDownload);
  657. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  658. prepend_path_to_filename(&p_sess->log_str);
  659. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  660. {
  661. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  662. return;
  663. }
  664. opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly);
  665. if (vsf_sysutil_retval_is_error(opened_file))
  666. {
  667. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
  668. return;
  669. }
  670. /* Lock file if required */
  671. if (tunable_lock_upload_files)
  672. {
  673. vsf_sysutil_lock_file_read(opened_file);
  674. }
  675. vsf_sysutil_fstat(opened_file, &s_p_statbuf);
  676. /* No games please */
  677. if (!vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  678. {
  679. /* Note - pretend open failed */
  680. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
  681. /* Irritating FireFox does RETR on directories, so avoid logging this
  682. * very common and noisy case.
  683. */
  684. if (vsf_sysutil_statbuf_is_dir(s_p_statbuf))
  685. {
  686. vsf_log_clear_entry(p_sess);
  687. }
  688. goto file_close_out;
  689. }
  690. /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems
  691. * such as XFS DMAPI.
  692. */
  693. vsf_sysutil_deactivate_noblock(opened_file);
  694. /* Optionally, we'll be paranoid and only serve publicly readable stuff */
  695. if (p_sess->is_anonymous && tunable_anon_world_readable_only &&
  696. !vsf_sysutil_statbuf_is_readable_other(s_p_statbuf))
  697. {
  698. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
  699. goto file_close_out;
  700. }
  701. /* Set the download offset (from REST) if any */
  702. if (offset != 0)
  703. {
  704. vsf_sysutil_lseek_to(opened_file, offset);
  705. }
  706. str_alloc_text(&s_mark_str, "Opening ");
  707. if (tunable_ascii_download_enable && p_sess->is_ascii)
  708. {
  709. str_append_text(&s_mark_str, "ASCII");
  710. is_ascii = 1;
  711. }
  712. else
  713. {
  714. str_append_text(&s_mark_str, "BINARY");
  715. }
  716. str_append_text(&s_mark_str, " mode data connection for ");
  717. str_append_str(&s_mark_str, &p_sess->ftp_arg_str);
  718. str_append_text(&s_mark_str, " (");
  719. str_append_filesize_t(&s_mark_str,
  720. vsf_sysutil_statbuf_get_size(s_p_statbuf));
  721. str_append_text(&s_mark_str, " bytes).");
  722. if (is_http)
  723. {
  724. remote_fd = VSFTP_COMMAND_FD;
  725. }
  726. else
  727. {
  728. remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&s_mark_str));
  729. if (vsf_sysutil_retval_is_error(remote_fd))
  730. {
  731. goto port_pasv_cleanup_out;
  732. }
  733. }
  734. trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
  735. opened_file, 0, is_ascii);
  736. if (!is_http &&
  737. vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 &&
  738. trans_ret.retval == 0)
  739. {
  740. trans_ret.retval = -2;
  741. }
  742. p_sess->transfer_size = trans_ret.transferred;
  743. /* Log _after_ the blocking dispose call, so we get transfer times right */
  744. if (trans_ret.retval == 0)
  745. {
  746. vsf_log_do_log(p_sess, 1);
  747. }
  748. if (is_http)
  749. {
  750. goto file_close_out;
  751. }
  752. /* Emit status message _after_ blocking dispose call to avoid buggy FTP
  753. * clients truncating the transfer.
  754. */
  755. if (trans_ret.retval == -1)
  756. {
  757. vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure reading local file.");
  758. }
  759. else if (trans_ret.retval == -2)
  760. {
  761. if (!p_sess->data_timeout)
  762. {
  763. vsf_cmdio_write(p_sess, FTP_BADSENDNET,
  764. "Failure writing network stream.");
  765. }
  766. }
  767. else
  768. {
  769. vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Transfer complete.");
  770. }
  771. check_abor(p_sess);
  772. port_pasv_cleanup_out:
  773. port_cleanup(p_sess);
  774. pasv_cleanup(p_sess);
  775. file_close_out:
  776. vsf_sysutil_close(opened_file);
  777. }
  778. static void
  779. handle_list(struct vsf_session* p_sess)
  780. {
  781. handle_dir_common(p_sess, 1, 0);
  782. }
  783. static void
  784. handle_dir_common(struct vsf_session* p_sess, int full_details, int stat_cmd)
  785. {
  786. static struct mystr s_option_str;
  787. static struct mystr s_filter_str;
  788. static struct mystr s_dir_name_str;
  789. static struct vsf_sysutil_statbuf* s_p_dirstat;
  790. int dir_allow_read = 1;
  791. struct vsf_sysutil_dir* p_dir = 0;
  792. int retval = 0;
  793. int use_control = 0;
  794. str_empty(&s_option_str);
  795. str_empty(&s_filter_str);
  796. /* By default open the current directory */
  797. str_alloc_text(&s_dir_name_str, ".");
  798. if (!stat_cmd && !data_transfer_checks_ok(p_sess))
  799. {
  800. return;
  801. }
  802. /* Do we have an option? Going to be strict here - the option must come
  803. * first. e.g. "ls -a .." fine, "ls .. -a" not fine
  804. */
  805. if (!str_isempty(&p_sess->ftp_arg_str) &&
  806. str_get_char_at(&p_sess->ftp_arg_str, 0) == '-')
  807. {
  808. /* Chop off the '-' */
  809. str_mid_to_end(&p_sess->ftp_arg_str, &s_option_str, 1);
  810. /* A space will separate options from filter (if any) */
  811. str_split_char(&s_option_str, &s_filter_str, ' ');
  812. }
  813. else
  814. {
  815. /* The argument, if any, is just a filter */
  816. str_copy(&s_filter_str, &p_sess->ftp_arg_str);
  817. }
  818. if (!str_isempty(&s_filter_str))
  819. {
  820. resolve_tilde(&s_filter_str, p_sess);
  821. if (!vsf_access_check_file(&s_filter_str))
  822. {
  823. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  824. return;
  825. }
  826. /* First check - is it an outright directory, as in "ls /pub" */
  827. p_dir = str_opendir(&s_filter_str);
  828. if (p_dir != 0)
  829. {
  830. /* Listing a directory! */
  831. str_copy(&s_dir_name_str, &s_filter_str);
  832. str_free(&s_filter_str);
  833. }
  834. else
  835. {
  836. struct str_locate_result locate_result =
  837. str_locate_char(&s_filter_str, '/');
  838. if (locate_result.found)
  839. {
  840. /* Includes a path! Reverse scan for / in the arg, to get the
  841. * base directory and filter (if any)
  842. */
  843. str_copy(&s_dir_name_str, &s_filter_str);
  844. str_split_char_reverse(&s_dir_name_str, &s_filter_str, '/');
  845. /* If we have e.g. "ls /.message", we just ripped off the leading
  846. * slash because it is the only one!
  847. */
  848. if (str_isempty(&s_dir_name_str))
  849. {
  850. str_alloc_text(&s_dir_name_str, "/");
  851. }
  852. }
  853. }
  854. }
  855. if (p_dir == 0)
  856. {
  857. /* NOTE - failure check done below, it's not forgotten */
  858. p_dir = str_opendir(&s_dir_name_str);
  859. }
  860. /* Fine, do it */
  861. if (stat_cmd)
  862. {
  863. use_control = 1;
  864. str_append_char(&s_option_str, 'a');
  865. vsf_cmdio_write_hyphen(p_sess, FTP_STATFILE_OK, "Status follows:");
  866. }
  867. else
  868. {
  869. int remote_fd = get_remote_transfer_fd(
  870. p_sess, "Here comes the directory listing.");
  871. if (vsf_sysutil_retval_is_error(remote_fd))
  872. {
  873. goto dir_close_out;
  874. }
  875. }
  876. if (p_sess->is_anonymous && p_dir && tunable_anon_world_readable_only)
  877. {
  878. vsf_sysutil_dir_stat(p_dir, &s_p_dirstat);
  879. if (!vsf_sysutil_statbuf_is_readable_other(s_p_dirstat))
  880. {
  881. dir_allow_read = 0;
  882. }
  883. }
  884. if (p_dir != 0 && dir_allow_read)
  885. {
  886. retval = vsf_ftpdataio_transfer_dir(p_sess, use_control, p_dir,
  887. &s_dir_name_str, &s_option_str,
  888. &s_filter_str, full_details);
  889. }
  890. if (!stat_cmd)
  891. {
  892. if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && retval == 0)
  893. {
  894. retval = -1;
  895. }
  896. }
  897. if (stat_cmd)
  898. {
  899. vsf_cmdio_write(p_sess, FTP_STATFILE_OK, "End of status");
  900. }
  901. else if (retval != 0)
  902. {
  903. if (!p_sess->data_timeout)
  904. {
  905. vsf_cmdio_write(p_sess, FTP_BADSENDNET,
  906. "Failure writing network stream.");
  907. }
  908. }
  909. else if (p_dir == 0 || !dir_allow_read)
  910. {
  911. vsf_cmdio_write(p_sess, FTP_TRANSFEROK,
  912. "Transfer done (but failed to open directory).");
  913. }
  914. else
  915. {
  916. vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Directory send OK.");
  917. }
  918. check_abor(p_sess);
  919. dir_close_out:
  920. if (p_dir)
  921. {
  922. vsf_sysutil_closedir(p_dir);
  923. }
  924. if (!stat_cmd)
  925. {
  926. port_cleanup(p_sess);
  927. pasv_cleanup(p_sess);
  928. }
  929. }
  930. static void
  931. handle_type(struct vsf_session* p_sess)
  932. {
  933. str_upper(&p_sess->ftp_arg_str);
  934. if (str_equal_text(&p_sess->ftp_arg_str, "I") ||
  935. str_equal_text(&p_sess->ftp_arg_str, "L8") ||
  936. str_equal_text(&p_sess->ftp_arg_str, "L 8"))
  937. {
  938. p_sess->is_ascii = 0;
  939. vsf_cmdio_write(p_sess, FTP_TYPEOK, "Switching to Binary mode.");
  940. }
  941. else if (str_equal_text(&p_sess->ftp_arg_str, "A") ||
  942. str_equal_text(&p_sess->ftp_arg_str, "A N"))
  943. {
  944. p_sess->is_ascii = 1;
  945. vsf_cmdio_write(p_sess, FTP_TYPEOK, "Switching to ASCII mode.");
  946. }
  947. else
  948. {
  949. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unrecognised TYPE command.");
  950. }
  951. }
  952. static void
  953. handle_port(struct vsf_session* p_sess)
  954. {
  955. unsigned short the_port;
  956. unsigned char vals[6];
  957. const unsigned char* p_raw;
  958. pasv_cleanup(p_sess);
  959. port_cleanup(p_sess);
  960. p_raw = vsf_sysutil_parse_uchar_string_sep(&p_sess->ftp_arg_str, ',', vals,
  961. sizeof(vals));
  962. if (p_raw == 0)
  963. {
  964. vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command.");
  965. return;
  966. }
  967. the_port = (unsigned short) ((vals[4] << 8) | vals[5]);
  968. vsf_sysutil_sockaddr_clone(&p_sess->p_port_sockaddr, p_sess->p_local_addr);
  969. vsf_sysutil_sockaddr_set_ipv4addr(p_sess->p_port_sockaddr, vals);
  970. vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, the_port);
  971. /* SECURITY:
  972. * 1) Reject requests not connecting to the control socket IP
  973. * 2) Reject connects to privileged ports
  974. */
  975. if (!tunable_port_promiscuous)
  976. {
  977. if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr,
  978. p_sess->p_port_sockaddr) ||
  979. vsf_sysutil_is_port_reserved(the_port))
  980. {
  981. vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command.");
  982. port_cleanup(p_sess);
  983. return;
  984. }
  985. }
  986. vsf_cmdio_write(p_sess, FTP_PORTOK,
  987. "PORT command successful. Consider using PASV.");
  988. }
  989. static void
  990. handle_stor(struct vsf_session* p_sess)
  991. {
  992. handle_upload_common(p_sess, 0, 0);
  993. }
  994. static void
  995. handle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique)
  996. {
  997. static struct vsf_sysutil_statbuf* s_p_statbuf;
  998. static struct mystr s_filename;
  999. struct mystr* p_filename;
  1000. struct vsf_transfer_ret trans_ret;
  1001. int new_file_fd;
  1002. int remote_fd;
  1003. int success = 0;
  1004. int created = 0;
  1005. int do_truncate = 0;
  1006. filesize_t offset = p_sess->restart_pos;
  1007. p_sess->restart_pos = 0;
  1008. if (!data_transfer_checks_ok(p_sess))
  1009. {
  1010. return;
  1011. }
  1012. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1013. p_filename = &p_sess->ftp_arg_str;
  1014. if (is_unique)
  1015. {
  1016. get_unique_filename(&s_filename, p_filename);
  1017. p_filename = &s_filename;
  1018. }
  1019. vsf_log_start_entry(p_sess, kVSFLogEntryUpload);
  1020. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1021. prepend_path_to_filename(&p_sess->log_str);
  1022. if (!vsf_access_check_file(p_filename))
  1023. {
  1024. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1025. return;
  1026. }
  1027. /* NOTE - actual file permissions will be governed by the tunable umask */
  1028. /* XXX - do we care about race between create and chown() of anonymous
  1029. * upload?
  1030. */
  1031. if (is_unique || (p_sess->is_anonymous && !tunable_anon_other_write_enable))
  1032. {
  1033. new_file_fd = str_create_exclusive(p_filename);
  1034. }
  1035. else
  1036. {
  1037. /* For non-anonymous, allow open() to overwrite or append existing files */
  1038. new_file_fd = str_create(p_filename);
  1039. if (!is_append && offset == 0)
  1040. {
  1041. do_truncate = 1;
  1042. }
  1043. }
  1044. if (vsf_sysutil_retval_is_error(new_file_fd))
  1045. {
  1046. vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create file.");
  1047. return;
  1048. }
  1049. created = 1;
  1050. vsf_sysutil_fstat(new_file_fd, &s_p_statbuf);
  1051. if (vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1052. {
  1053. /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems
  1054. * such as XFS DMAPI.
  1055. */
  1056. vsf_sysutil_deactivate_noblock(new_file_fd);
  1057. }
  1058. /* Are we required to chown() this file for security? */
  1059. if (p_sess->is_anonymous && tunable_chown_uploads)
  1060. {
  1061. vsf_sysutil_fchmod(new_file_fd, tunable_chown_upload_mode);
  1062. if (tunable_one_process_model)
  1063. {
  1064. vsf_one_process_chown_upload(p_sess, new_file_fd);
  1065. }
  1066. else
  1067. {
  1068. vsf_two_process_chown_upload(p_sess, new_file_fd);
  1069. }
  1070. }
  1071. /* Are we required to lock this file? */
  1072. if (tunable_lock_upload_files)
  1073. {
  1074. vsf_sysutil_lock_file_write(new_file_fd);
  1075. }
  1076. /* Must truncate the file AFTER locking it! */
  1077. if (do_truncate)
  1078. {
  1079. vsf_sysutil_ftruncate(new_file_fd);
  1080. vsf_sysutil_lseek_to(new_file_fd, 0);
  1081. }
  1082. if (!is_append && offset != 0)
  1083. {
  1084. /* XXX - warning, allows seek past end of file! Check for seek > size? */
  1085. vsf_sysutil_lseek_to(new_file_fd, offset);
  1086. }
  1087. else if (is_append)
  1088. {
  1089. vsf_sysutil_lseek_end(new_file_fd);
  1090. }
  1091. if (is_unique)
  1092. {
  1093. struct mystr resp_str = INIT_MYSTR;
  1094. str_alloc_text(&resp_str, "FILE: ");
  1095. str_append_str(&resp_str, p_filename);
  1096. remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&resp_str));
  1097. str_free(&resp_str);
  1098. }
  1099. else
  1100. {
  1101. remote_fd = get_remote_transfer_fd(p_sess, "Ok to send data.");
  1102. }
  1103. if (vsf_sysutil_retval_is_error(remote_fd))
  1104. {
  1105. goto port_pasv_cleanup_out;
  1106. }
  1107. if (tunable_ascii_upload_enable && p_sess->is_ascii)
  1108. {
  1109. trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
  1110. new_file_fd, 1, 1);
  1111. }
  1112. else
  1113. {
  1114. trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
  1115. new_file_fd, 1, 0);
  1116. }
  1117. if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && trans_ret.retval == 0)
  1118. {
  1119. trans_ret.retval = -2;
  1120. }
  1121. p_sess->transfer_size = trans_ret.transferred;
  1122. if (trans_ret.retval == 0)
  1123. {
  1124. success = 1;
  1125. vsf_log_do_log(p_sess, 1);
  1126. }
  1127. if (trans_ret.retval == -1)
  1128. {
  1129. vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file.");
  1130. }
  1131. else if (trans_ret.retval == -2)
  1132. {
  1133. if (!p_sess->data_timeout)
  1134. {
  1135. vsf_cmdio_write(p_sess, FTP_BADSENDNET,
  1136. "Failure reading network stream.");
  1137. }
  1138. }
  1139. else
  1140. {
  1141. vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Transfer complete.");
  1142. }
  1143. check_abor(p_sess);
  1144. port_pasv_cleanup_out:
  1145. port_cleanup(p_sess);
  1146. pasv_cleanup(p_sess);
  1147. if (tunable_delete_failed_uploads && created && !success)
  1148. {
  1149. str_unlink(p_filename);
  1150. }
  1151. vsf_sysutil_close(new_file_fd);
  1152. }
  1153. static void
  1154. handle_mkd(struct vsf_session* p_sess)
  1155. {
  1156. int retval;
  1157. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1158. vsf_log_start_entry(p_sess, kVSFLogEntryMkdir);
  1159. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1160. prepend_path_to_filename(&p_sess->log_str);
  1161. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1162. {
  1163. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1164. return;
  1165. }
  1166. /* NOTE! Actual permissions will be governed by the tunable umask */
  1167. retval = str_mkdir(&p_sess->ftp_arg_str, 0777);
  1168. if (retval != 0)
  1169. {
  1170. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1171. "Create directory operation failed.");
  1172. return;
  1173. }
  1174. vsf_log_do_log(p_sess, 1);
  1175. {
  1176. static struct mystr s_mkd_res;
  1177. static struct mystr s_tmp_str;
  1178. str_copy(&s_tmp_str, &p_sess->ftp_arg_str);
  1179. prepend_path_to_filename(&s_tmp_str);
  1180. /* Double up double quotes */
  1181. str_replace_text(&s_tmp_str, "\"", "\"\"");
  1182. /* Build result string */
  1183. str_alloc_text(&s_mkd_res, "\"");
  1184. str_append_str(&s_mkd_res, &s_tmp_str);
  1185. str_append_text(&s_mkd_res, "\" created");
  1186. vsf_cmdio_write_str(p_sess, FTP_MKDIROK, &s_mkd_res);
  1187. }
  1188. }
  1189. static void
  1190. handle_rmd(struct vsf_session* p_sess)
  1191. {
  1192. int retval;
  1193. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1194. vsf_log_start_entry(p_sess, kVSFLogEntryRmdir);
  1195. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1196. prepend_path_to_filename(&p_sess->log_str);
  1197. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1198. {
  1199. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1200. return;
  1201. }
  1202. retval = str_rmdir(&p_sess->ftp_arg_str);
  1203. if (retval != 0)
  1204. {
  1205. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1206. "Remove directory operation failed.");
  1207. }
  1208. else
  1209. {
  1210. vsf_log_do_log(p_sess, 1);
  1211. vsf_cmdio_write(p_sess, FTP_RMDIROK,
  1212. "Remove directory operation successful.");
  1213. }
  1214. }
  1215. static void
  1216. handle_dele(struct vsf_session* p_sess)
  1217. {
  1218. int retval;
  1219. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1220. vsf_log_start_entry(p_sess, kVSFLogEntryDelete);
  1221. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1222. prepend_path_to_filename(&p_sess->log_str);
  1223. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1224. {
  1225. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1226. return;
  1227. }
  1228. retval = str_unlink(&p_sess->ftp_arg_str);
  1229. if (retval != 0)
  1230. {
  1231. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Delete operation failed.");
  1232. }
  1233. else
  1234. {
  1235. vsf_log_do_log(p_sess, 1);
  1236. vsf_cmdio_write(p_sess, FTP_DELEOK, "Delete operation successful.");
  1237. }
  1238. }
  1239. static void
  1240. handle_rest(struct vsf_session* p_sess)
  1241. {
  1242. static struct mystr s_rest_str;
  1243. filesize_t val = str_a_to_filesize_t(&p_sess->ftp_arg_str);
  1244. if (val < 0)
  1245. {
  1246. val = 0;
  1247. }
  1248. p_sess->restart_pos = val;
  1249. str_alloc_text(&s_rest_str, "Restart position accepted (");
  1250. str_append_filesize_t(&s_rest_str, val);
  1251. str_append_text(&s_rest_str, ").");
  1252. vsf_cmdio_write_str(p_sess, FTP_RESTOK, &s_rest_str);
  1253. }
  1254. static void
  1255. handle_rnfr(struct vsf_session* p_sess)
  1256. {
  1257. static struct vsf_sysutil_statbuf* p_statbuf;
  1258. int retval;
  1259. /* Clear old value */
  1260. str_free(&p_sess->rnfr_filename_str);
  1261. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1262. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1263. {
  1264. vsf_log_start_entry(p_sess, kVSFLogEntryRename);
  1265. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1266. prepend_path_to_filename(&p_sess->log_str);
  1267. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1268. return;
  1269. }
  1270. /* Does it exist? */
  1271. retval = str_stat(&p_sess->ftp_arg_str, &p_statbuf);
  1272. if (retval == 0)
  1273. {
  1274. /* Yes */
  1275. str_copy(&p_sess->rnfr_filename_str, &p_sess->ftp_arg_str);
  1276. vsf_cmdio_write(p_sess, FTP_RNFROK, "Ready for RNTO.");
  1277. }
  1278. else
  1279. {
  1280. vsf_log_start_entry(p_sess, kVSFLogEntryRename);
  1281. str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  1282. prepend_path_to_filename(&p_sess->log_str);
  1283. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "RNFR command failed.");
  1284. }
  1285. }
  1286. static void
  1287. handle_rnto(struct vsf_session* p_sess)
  1288. {
  1289. static struct mystr s_tmp_str;
  1290. int retval;
  1291. /* If we didn't get a RNFR, throw a wobbly */
  1292. if (str_isempty(&p_sess->rnfr_filename_str))
  1293. {
  1294. vsf_cmdio_write(p_sess, FTP_NEEDRNFR,
  1295. "RNFR required first.");
  1296. return;
  1297. }
  1298. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1299. vsf_log_start_entry(p_sess, kVSFLogEntryRename);
  1300. str_copy(&p_sess->log_str, &p_sess->rnfr_filename_str);
  1301. prepend_path_to_filename(&p_sess->log_str);
  1302. str_append_char(&p_sess->log_str, ' ');
  1303. str_copy(&s_tmp_str, &p_sess->ftp_arg_str);
  1304. prepend_path_to_filename(&s_tmp_str);
  1305. str_append_str(&p_sess->log_str, &s_tmp_str);
  1306. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1307. {
  1308. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1309. return;
  1310. }
  1311. /* NOTE - might overwrite destination file. Not a concern because the same
  1312. * could be accomplished with DELE.
  1313. */
  1314. retval = str_rename(&p_sess->rnfr_filename_str, &p_sess->ftp_arg_str);
  1315. /* Clear the RNFR filename; start the two stage process again! */
  1316. str_free(&p_sess->rnfr_filename_str);
  1317. if (retval == 0)
  1318. {
  1319. vsf_log_do_log(p_sess, 1);
  1320. vsf_cmdio_write(p_sess, FTP_RENAMEOK, "Rename successful.");
  1321. }
  1322. else
  1323. {
  1324. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Rename failed.");
  1325. }
  1326. }
  1327. static void
  1328. handle_nlst(struct vsf_session* p_sess)
  1329. {
  1330. handle_dir_common(p_sess, 0, 0);
  1331. }
  1332. static void
  1333. prepend_path_to_filename(struct mystr* p_str)
  1334. {
  1335. static struct mystr s_tmp_str;
  1336. /* Only prepend current working directory if the incoming filename is
  1337. * relative
  1338. */
  1339. str_empty(&s_tmp_str);
  1340. if (str_isempty(p_str) || str_get_char_at(p_str, 0) != '/')
  1341. {
  1342. str_getcwd(&s_tmp_str);
  1343. /* Careful to not emit // if we are in directory / (common with chroot) */
  1344. if (str_isempty(&s_tmp_str) ||
  1345. str_get_char_at(&s_tmp_str, str_getlen(&s_tmp_str) - 1) != '/')
  1346. {
  1347. str_append_char(&s_tmp_str, '/');
  1348. }
  1349. }
  1350. str_append_str(&s_tmp_str, p_str);
  1351. str_copy(p_str, &s_tmp_str);
  1352. }
  1353. static void
  1354. handle_sigurg(void* p_private)
  1355. {
  1356. struct mystr async_cmd_str = INIT_MYSTR;
  1357. struct mystr async_arg_str = INIT_MYSTR;
  1358. struct mystr real_cmd_str = INIT_MYSTR;
  1359. unsigned int len;
  1360. struct vsf_session* p_sess = (struct vsf_session*) p_private;
  1361. /* Did stupid client sent something OOB without a data connection? */
  1362. if (p_sess->data_fd == -1)
  1363. {
  1364. return;
  1365. }
  1366. /* Get the async command - blocks (use data timeout alarm) */
  1367. vsf_cmdio_get_cmd_and_arg(p_sess, &async_cmd_str, &async_arg_str, 0);
  1368. /* Chop off first four characters; they are telnet characters. The client
  1369. * should have sent the first two normally and the second two as urgent
  1370. * data.
  1371. */
  1372. len = str_getlen(&async_cmd_str);
  1373. if (len >= 4)
  1374. {
  1375. str_right(&async_cmd_str, &real_cmd_str, len - 4);
  1376. }
  1377. if (str_equal_text(&real_cmd_str, "ABOR"))
  1378. {
  1379. p_sess->abor_received = 1;
  1380. /* This is failok because of a small race condition; the SIGURG might
  1381. * be raised after the data socket is closed, but before data_fd is
  1382. * set to -1.
  1383. */
  1384. vsf_sysutil_shutdown_failok(p_sess->data_fd);
  1385. }
  1386. else
  1387. {
  1388. /* Sorry! */
  1389. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
  1390. }
  1391. str_free(&async_cmd_str);
  1392. str_free(&async_arg_str);
  1393. str_free(&real_cmd_str);
  1394. }
  1395. static int
  1396. get_remote_transfer_fd(struct vsf_session* p_sess, const char* p_status_msg)
  1397. {
  1398. int remote_fd;
  1399. if (!pasv_active(p_sess) && !port_active(p_sess))
  1400. {
  1401. bug("neither PORT nor PASV active in get_remote_transfer_fd");
  1402. }
  1403. p_sess->abor_received = 0;
  1404. if (pasv_active(p_sess))
  1405. {
  1406. remote_fd = vsf_ftpdataio_get_pasv_fd(p_sess);
  1407. }
  1408. else
  1409. {
  1410. remote_fd = vsf_ftpdataio_get_port_fd(p_sess);
  1411. }
  1412. if (vsf_sysutil_retval_is_error(remote_fd))
  1413. {
  1414. return remote_fd;
  1415. }
  1416. vsf_cmdio_write(p_sess, FTP_DATACONN, p_status_msg);
  1417. if (vsf_ftpdataio_post_mark_connect(p_sess) != 1)
  1418. {
  1419. vsf_ftpdataio_dispose_transfer_fd(p_sess);
  1420. return -1;
  1421. }
  1422. return remote_fd;
  1423. }
  1424. static void
  1425. check_abor(struct vsf_session* p_sess)
  1426. {
  1427. /* If the client sent ABOR, respond to it here */
  1428. if (p_sess->abor_received)
  1429. {
  1430. p_sess->abor_received = 0;
  1431. vsf_cmdio_write(p_sess, FTP_ABOROK, "ABOR successful.");
  1432. }
  1433. }
  1434. static void
  1435. handle_size(struct vsf_session* p_sess)
  1436. {
  1437. /* Note - in ASCII mode, are supposed to return the size after taking into
  1438. * account ASCII linefeed conversions. At least this is what wu-ftpd does in
  1439. * version 2.6.1. Proftpd-1.2.0pre fails to do this.
  1440. * I will not do it because it is a potential I/O DoS.
  1441. */
  1442. static struct vsf_sysutil_statbuf* s_p_statbuf;
  1443. int retval;
  1444. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1445. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1446. {
  1447. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1448. return;
  1449. }
  1450. retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
  1451. if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1452. {
  1453. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Could not get file size.");
  1454. }
  1455. else
  1456. {
  1457. static struct mystr s_size_res_str;
  1458. str_alloc_filesize_t(&s_size_res_str,
  1459. vsf_sysutil_statbuf_get_size(s_p_statbuf));
  1460. vsf_cmdio_write_str(p_sess, FTP_SIZEOK, &s_size_res_str);
  1461. }
  1462. }
  1463. static void
  1464. handle_site(struct vsf_session* p_sess)
  1465. {
  1466. static struct mystr s_site_args_str;
  1467. /* What SITE sub-command is it? */
  1468. str_split_char(&p_sess->ftp_arg_str, &s_site_args_str, ' ');
  1469. str_upper(&p_sess->ftp_arg_str);
  1470. if (tunable_write_enable &&
  1471. tunable_chmod_enable &&
  1472. str_equal_text(&p_sess->ftp_arg_str, "CHMOD"))
  1473. {
  1474. handle_site_chmod(p_sess, &s_site_args_str);
  1475. }
  1476. else if (str_equal_text(&p_sess->ftp_arg_str, "UMASK"))
  1477. {
  1478. handle_site_umask(p_sess, &s_site_args_str);
  1479. }
  1480. else if (str_equal_text(&p_sess->ftp_arg_str, "HELP"))
  1481. {
  1482. if (tunable_write_enable &&
  1483. tunable_chmod_enable)
  1484. {
  1485. vsf_cmdio_write(p_sess, FTP_SITEHELP, "CHMOD UMASK HELP");
  1486. }
  1487. else
  1488. {
  1489. vsf_cmdio_write(p_sess, FTP_SITEHELP, "UMASK HELP");
  1490. }
  1491. }
  1492. else
  1493. {
  1494. vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown SITE command.");
  1495. }
  1496. }
  1497. static void
  1498. handle_site_chmod(struct vsf_session* p_sess, struct mystr* p_arg_str)
  1499. {
  1500. static struct mystr s_chmod_file_str;
  1501. unsigned int perms;
  1502. int retval;
  1503. if (str_isempty(p_arg_str))
  1504. {
  1505. vsf_cmdio_write(p_sess, FTP_BADCMD, "SITE CHMOD needs 2 arguments.");
  1506. return;
  1507. }
  1508. str_split_char(p_arg_str, &s_chmod_file_str, ' ');
  1509. if (str_isempty(&s_chmod_file_str))
  1510. {
  1511. vsf_cmdio_write(p_sess, FTP_BADCMD, "SITE CHMOD needs 2 arguments.");
  1512. return;
  1513. }
  1514. resolve_tilde(&s_chmod_file_str, p_sess);
  1515. vsf_log_start_entry(p_sess, kVSFLogEntryChmod);
  1516. str_copy(&p_sess->log_str, &s_chmod_file_str);
  1517. prepend_path_to_filename(&p_sess->log_str);
  1518. str_append_char(&p_sess->log_str, ' ');
  1519. str_append_str(&p_sess->log_str, p_arg_str);
  1520. if (!vsf_access_check_file(&s_chmod_file_str))
  1521. {
  1522. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1523. return;
  1524. }
  1525. /* Don't worry - our chmod() implementation only allows 0 - 0777 */
  1526. perms = str_octal_to_uint(p_arg_str);
  1527. retval = str_chmod(&s_chmod_file_str, perms);
  1528. if (vsf_sysutil_retval_is_error(retval))
  1529. {
  1530. vsf_cmdio_write(p_sess, FTP_FILEFAIL, "SITE CHMOD command failed.");
  1531. }
  1532. else
  1533. {
  1534. vsf_log_do_log(p_sess, 1);
  1535. vsf_cmdio_write(p_sess, FTP_CHMODOK, "SITE CHMOD command ok.");
  1536. }
  1537. }
  1538. static void
  1539. handle_site_umask(struct vsf_session* p_sess, struct mystr* p_arg_str)
  1540. {
  1541. static struct mystr s_umask_resp_str;
  1542. if (str_isempty(p_arg_str))
  1543. {
  1544. /* Empty arg => report current umask */
  1545. str_alloc_text(&s_umask_resp_str, "Your current UMASK is ");
  1546. str_append_text(&s_umask_resp_str,
  1547. vsf_sysutil_uint_to_octal(vsf_sysutil_get_umask()));
  1548. }
  1549. else
  1550. {
  1551. /* Set current umask */
  1552. unsigned int new_umask = str_octal_to_uint(p_arg_str);
  1553. vsf_sysutil_set_umask(new_umask);
  1554. str_alloc_text(&s_umask_resp_str, "UMASK set to ");
  1555. str_append_text(&s_umask_resp_str,
  1556. vsf_sysutil_uint_to_octal(vsf_sysutil_get_umask()));
  1557. }
  1558. vsf_cmdio_write_str(p_sess, FTP_UMASKOK, &s_umask_resp_str);
  1559. }
  1560. static void
  1561. handle_appe(struct vsf_session* p_sess)
  1562. {
  1563. handle_upload_common(p_sess, 1, 0);
  1564. }
  1565. static void
  1566. handle_mdtm(struct vsf_session* p_sess)
  1567. {
  1568. static struct mystr s_filename_str;
  1569. static struct vsf_sysutil_statbuf* s_p_statbuf;
  1570. int do_write = 0;
  1571. long modtime = 0;
  1572. struct str_locate_result loc = str_locate_char(&p_sess->ftp_arg_str, ' ');
  1573. int retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
  1574. if (tunable_mdtm_write && retval != 0 && loc.found &&
  1575. vsf_sysutil_isdigit(str_get_char_at(&p_sess->ftp_arg_str, 0)))
  1576. {
  1577. if (loc.index == 8 || loc.index == 14 ||
  1578. (loc.index > 15 && str_get_char_at(&p_sess->ftp_arg_str, 14) == '.'))
  1579. {
  1580. do_write = 1;
  1581. }
  1582. }
  1583. if (do_write != 0)
  1584. {
  1585. str_split_char(&p_sess->ftp_arg_str, &s_filename_str, ' ');
  1586. modtime = vsf_sysutil_parse_time(str_getbuf(&p_sess->ftp_arg_str));
  1587. str_copy(&p_sess->ftp_arg_str, &s_filename_str);
  1588. }
  1589. resolve_tilde(&p_sess->ftp_arg_str, p_sess);
  1590. if (!vsf_access_check_file(&p_sess->ftp_arg_str))
  1591. {
  1592. vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
  1593. return;
  1594. }
  1595. if (do_write && tunable_write_enable &&
  1596. (tunable_anon_other_write_enable || !p_sess->is_anonymous))
  1597. {
  1598. retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf);
  1599. if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1600. {
  1601. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1602. "Could not set file modification time.");
  1603. }
  1604. else
  1605. {
  1606. retval = vsf_sysutil_setmodtime(
  1607. str_getbuf(&p_sess->ftp_arg_str), modtime, tunable_use_localtime);
  1608. if (retval != 0)
  1609. {
  1610. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1611. "Could not set file modification time.");
  1612. }
  1613. else
  1614. {
  1615. vsf_cmdio_write(p_sess, FTP_MDTMOK,
  1616. "File modification time set.");
  1617. }
  1618. }
  1619. }
  1620. else
  1621. {
  1622. if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  1623. {
  1624. vsf_cmdio_write(p_sess, FTP_FILEFAIL,
  1625. "Could not get file modification time.");
  1626. }
  1627. else
  1628. {
  1629. static struct mystr s_mdtm_res_str;
  1630. str_alloc_text(&s_mdtm_res_str,
  1631. vsf_sysutil_statbuf_get_numeric_date(
  1632. s_p_statbuf, tunable_use_localtime));
  1633. vsf_cmdio_write_str(p_sess, FTP_MDTMOK, &s_mdtm_res_str);
  1634. }
  1635. }
  1636. }
  1637. static void
  1638. handle_eprt(struct vsf_session* p_sess)
  1639. {
  1640. static struct mystr s_part1_str;
  1641. static struct mystr s_part2_str;
  1642. static struct mystr s_scopeid_str;
  1643. int proto;
  1644. int port;
  1645. const unsigned char* p_raw_addr;
  1646. int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  1647. port_cleanup(p_sess);
  1648. pasv_cleanup(p_sess);
  1649. str_copy(&s_part1_str, &p_sess->ftp_arg_str);
  1650. str_split_char(&s_part1_str, &s_part2_str, '|');
  1651. if (!str_isempty(&s_part1_str))
  1652. {
  1653. goto bad_eprt;
  1654. }
  1655. /* Split out the protocol and check it */
  1656. str_split_char(&s_part2_str, &s_part1_str, '|');
  1657. proto = str_atoi(&s_part2_str);
  1658. if (proto < 1 || proto > 2 || (!is_ipv6 && proto == 2))
  1659. {
  1660. vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT protocol.");
  1661. return;
  1662. }
  1663. /* Split out address and parse it */
  1664. str_split_char(&s_part1_str, &s_part2_str, '|');
  1665. if (proto == 2)
  1666. {
  1667. str_split_char(&s_part1_str, &s_scopeid_str, '%');
  1668. p_raw_addr = vsf_sysutil_parse_ipv6(&s_part1_str);
  1669. }
  1670. else
  1671. {
  1672. p_raw_addr = vsf_sysutil_parse_ipv4(&s_part1_str);
  1673. }
  1674. if (!p_raw_addr)
  1675. {
  1676. goto bad_eprt;
  1677. }
  1678. /* Split out port and parse it */
  1679. str_split_char(&s_part2_str, &s_part1_str, '|');
  1680. if (!str_isempty(&s_part1_str) || str_isempty(&s_part2_str))
  1681. {
  1682. goto bad_eprt;
  1683. }
  1684. port = str_atoi(&s_part2_str);
  1685. if (port < 0 || port > 65535)
  1686. {
  1687. goto bad_eprt;
  1688. }
  1689. vsf_sysutil_sockaddr_clone(&p_sess->p_port_sockaddr, p_sess->p_local_addr);
  1690. if (proto == 2)
  1691. {
  1692. vsf_sysutil_sockaddr_set_ipv6addr(p_sess->p_port_sockaddr, p_raw_addr);
  1693. }
  1694. else
  1695. {
  1696. vsf_sysutil_sockaddr_set_ipv4addr(p_sess->p_port_sockaddr, p_raw_addr);
  1697. }
  1698. vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, (unsigned short) port);
  1699. /* SECURITY:
  1700. * 1) Reject requests not connecting to the control socket IP
  1701. * 2) Reject connects to privileged ports
  1702. */
  1703. if (!tunable_port_promiscuous)
  1704. {
  1705. if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr,
  1706. p_sess->p_port_sockaddr) ||
  1707. vsf_sysutil_is_port_reserved((unsigned short) port))
  1708. {
  1709. vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal EPRT command.");
  1710. port_cleanup(p_sess);
  1711. return;
  1712. }
  1713. }
  1714. vsf_cmdio_write(p_sess, FTP_EPRTOK,
  1715. "EPRT command successful. Consider using EPSV.");
  1716. return;
  1717. bad_eprt:
  1718. vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command.");
  1719. }
  1720. /* XXX - add AUTH etc. */
  1721. static void
  1722. handle_help(struct vsf_session* p_sess)
  1723. {
  1724. vsf_cmdio_write_hyphen(p_sess, FTP_HELP,
  1725. "The following commands are recognized.");
  1726. vsf_cmdio_write_raw(p_sess,
  1727. " ABOR ACCT ALLO APPE CDUP CWD DELE EPRT EPSV FEAT HELP LIST MDTM MKD\r\n");
  1728. vsf_cmdio_write_raw(p_sess,
  1729. " MODE NLST NOOP OPTS PASS PASV PORT PWD QUIT REIN REST RETR RMD RNFR\r\n");
  1730. vsf_cmdio_write_raw(p_sess,
  1731. " RNTO SITE SIZE SMNT STAT STOR STOU STRU SYST TYPE USER XCUP XCWD XMKD\r\n");
  1732. vsf_cmdio_write_raw(p_sess,
  1733. " XPWD XRMD\r\n");
  1734. vsf_cmdio_write(p_sess, FTP_HELP, "Help OK.");
  1735. }
  1736. static void
  1737. handle_stou(struct vsf_session* p_sess)
  1738. {
  1739. handle_upload_common(p_sess, 0, 1);
  1740. }
  1741. static void
  1742. get_unique_filename(struct mystr* p_outstr, const struct mystr* p_base_str)
  1743. {
  1744. /* Use silly wu-ftpd algorithm for compatibility. It has races of course, if
  1745. * two sessions are using the same file prefix at the same time.
  1746. */
  1747. static struct vsf_sysutil_statbuf* s_p_statbuf;
  1748. static struct mystr s_stou_str;
  1749. unsigned int suffix = 1;
  1750. const struct mystr* p_real_base_str = p_base_str;
  1751. int retval;
  1752. if (str_isempty(p_real_base_str))
  1753. {
  1754. str_alloc_text(&s_stou_str, "STOU");
  1755. p_real_base_str = &s_stou_str;
  1756. }
  1757. else
  1758. {
  1759. /* Do not add any suffix at all if the name is not taken. */
  1760. retval = str_stat(p_real_base_str, &s_p_statbuf);
  1761. if (vsf_sysutil_retval_is_error(retval))
  1762. {
  1763. str_copy(p_outstr, p_real_base_str);
  1764. return;
  1765. }
  1766. }
  1767. while (1)
  1768. {
  1769. str_copy(p_outstr, p_real_base_str);
  1770. str_append_char(p_outstr, '.');
  1771. str_append_ulong(p_outstr, suffix);
  1772. retval = str_stat(p_outstr, &s_p_statbuf);
  1773. if (vsf_sysutil_retval_is_error(retval))
  1774. {
  1775. return;
  1776. }
  1777. ++suffix;
  1778. }
  1779. }
  1780. static void
  1781. handle_stat(struct vsf_session* p_sess)
  1782. {
  1783. vsf_cmdio_write_hyphen(p_sess, FTP_STATOK, "FTP server status:");
  1784. vsf_cmdio_write_raw(p_sess, " Connected to ");
  1785. vsf_cmdio_write_raw(p_sess, str_getbuf(&p_sess->remote_ip_str));
  1786. vsf_cmdio_write_raw(p_sess, "\r\n");
  1787. vsf_cmdio_write_raw(p_sess, " Logged in as ");
  1788. vsf_cmdio_write_raw(p_sess, str_getbuf(&p_sess->user_str));
  1789. vsf_cmdio_write_raw(p_sess, "\r\n");
  1790. vsf_cmdio_write_raw(p_sess, " TYPE: ");
  1791. if (p_sess->is_ascii)
  1792. {
  1793. vsf_cmdio_write_raw(p_sess, "ASCII\r\n");
  1794. }
  1795. else
  1796. {
  1797. vsf_cmdio_write_raw(p_sess, "BINARY\r\n");
  1798. }
  1799. if (p_sess->bw_rate_max == 0)
  1800. {
  1801. vsf_cmdio_write_raw(p_sess, " No session bandwidth limit\r\n");
  1802. }
  1803. else
  1804. {
  1805. vsf_cmdio_write_raw(p_sess, " Session bandwidth limit in byte/s is ");
  1806. vsf_cmdio_write_raw(p_sess, vsf_sysutil_ulong_to_str(p_sess->bw_rate_max));
  1807. vsf_cmdio_write_raw(p_sess, "\r\n");
  1808. }
  1809. if (tunable_idle_session_timeout == 0)
  1810. {
  1811. vsf_cmdio_write_raw(p_sess, " No session timeout\r\n");
  1812. }
  1813. else
  1814. {
  1815. vsf_cmdio_write_raw(p_sess, " Session timeout in seconds is ");
  1816. vsf_cmdio_write_raw(p_sess,
  1817. vsf_sysutil_ulong_to_str(tunable_idle_session_timeout));
  1818. vsf_cmdio_write_raw(p_sess, "\r\n");
  1819. }
  1820. if (p_sess->control_use_ssl)
  1821. {
  1822. vsf_cmdio_write_raw(p_sess, " Control connection is encrypted\r\n");
  1823. }
  1824. else
  1825. {
  1826. vsf_cmdio_write_raw(p_sess, " Control connection is plain text\r\n");
  1827. }
  1828. if (p_sess->data_use_ssl)
  1829. {
  1830. vsf_cmdio_write_raw(p_sess, " Data connections will be encrypted\r\n");
  1831. }
  1832. else
  1833. {
  1834. vsf_cmdio_write_raw(p_sess, " Data connections will be plain text\r\n");
  1835. }
  1836. if (p_sess->num_clients > 0)
  1837. {
  1838. vsf_cmdio_write_raw(p_sess, " At session startup, client count was ");
  1839. vsf_cmdio_write_raw(p_sess, vsf_sysutil_ulong_to_str(p_sess->num_clients));
  1840. vsf_cmdio_write_raw(p_sess, "\r\n");
  1841. }
  1842. vsf_cmdio_write_raw(p_sess,
  1843. " vsFTPd " VSF_VERSION " - secure, fast, stable\r\n");
  1844. vsf_cmdio_write(p_sess, FTP_STATOK, "End of status");
  1845. }
  1846. static void
  1847. handle_stat_file(struct vsf_session* p_sess)
  1848. {
  1849. handle_dir_common(p_sess, 1, 1);
  1850. }
  1851. static int
  1852. data_transfer_checks_ok(struct vsf_session* p_sess)
  1853. {
  1854. if (!pasv_active(p_sess) && !port_active(p_sess))
  1855. {
  1856. vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
  1857. return 0;
  1858. }
  1859. if (tunable_ssl_enable && !p_sess->data_use_ssl &&
  1860. ((tunable_force_local_data_ssl && !p_sess->is_anonymous) ||
  1861. (tunable_force_anon_data_ssl && p_sess->is_anonymous)))
  1862. {
  1863. vsf_cmdio_write(
  1864. p_sess, FTP_NEEDENCRYPT, "Data connections must be encrypted.");
  1865. return 0;
  1866. }
  1867. return 1;
  1868. }
  1869. static void
  1870. resolve_tilde(struct mystr* p_str, struct vsf_session* p_sess)
  1871. {
  1872. unsigned int len = str_getlen(p_str);
  1873. if (len > 0 && str_get_char_at(p_str, 0) == '~')
  1874. {
  1875. static struct mystr s_rhs_str;
  1876. if (len == 1 || str_get_char_at(p_str, 1) == '/')
  1877. {
  1878. str_split_char(p_str, &s_rhs_str, '~');
  1879. str_copy(p_str, &p_sess->home_str);
  1880. str_append_str(p_str, &s_rhs_str);
  1881. }
  1882. else if (tunable_tilde_user_enable && len > 1)
  1883. {
  1884. static struct mystr s_user_str;
  1885. struct vsf_sysutil_user* p_user;
  1886. str_copy(&s_rhs_str, p_str);
  1887. str_split_char(&s_rhs_str, &s_user_str, '~');
  1888. str_split_char(&s_user_str, &s_rhs_str, '/');
  1889. p_user = str_getpwnam(&s_user_str);
  1890. if (p_user != 0)
  1891. {
  1892. str_alloc_text(p_str, vsf_sysutil_user_get_homedir(p_user));
  1893. if (!str_isempty(&s_rhs_str))
  1894. {
  1895. str_append_char(p_str, '/');
  1896. str_append_str(p_str, &s_rhs_str);
  1897. }
  1898. }
  1899. }
  1900. }
  1901. }
  1902. static void handle_logged_in_user(struct vsf_session* p_sess)
  1903. {
  1904. if (p_sess->is_anonymous)
  1905. {
  1906. vsf_cmdio_write(p_sess, FTP_LOGINERR, "Can't change from guest user.");
  1907. }
  1908. else if (str_equal(&p_sess->user_str, &p_sess->ftp_arg_str))
  1909. {
  1910. vsf_cmdio_write(p_sess, FTP_GIVEPWORD, "Any password will do.");
  1911. }
  1912. else
  1913. {
  1914. vsf_cmdio_write(p_sess, FTP_LOGINERR, "Can't change to another user.");
  1915. }
  1916. }
  1917. static void handle_logged_in_pass(struct vsf_session* p_sess)
  1918. {
  1919. vsf_cmdio_write(p_sess, FTP_LOGINOK, "Already logged in.");
  1920. }
  1921. static void
  1922. handle_http(struct vsf_session* p_sess)
  1923. {
  1924. /* Warning: Doesn't respect cmds_allowed etc. because there is currently only
  1925. * one command (GET)!
  1926. * HTTP likely doesn't respect other important FTP options. I don't think
  1927. * logging works.
  1928. */
  1929. if (!tunable_download_enable)
  1930. {
  1931. bug("HTTP needs download - fix your config");
  1932. }
  1933. /* Eat the HTTP headers, which we don't care about. */
  1934. do
  1935. {
  1936. vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str,
  1937. &p_sess->ftp_arg_str, 1);
  1938. }
  1939. while (!str_isempty(&p_sess->ftp_cmd_str) ||
  1940. !str_isempty(&p_sess->ftp_arg_str));
  1941. vsf_cmdio_write_raw(p_sess, "HTTP/1.1 200 OK\r\n");
  1942. vsf_cmdio_write_raw(p_sess, "ftpz alpha\r\n");
  1943. vsf_cmdio_write_raw(p_sess, "Connection: close\r\n");
  1944. vsf_cmdio_write_raw(p_sess, "X-Frame-Options: SAMEORIGIN\r\n");
  1945. vsf_cmdio_write_raw(p_sess, "X-Content-Type-Options: nosniff\r\n");
  1946. /* Split the path from the HTTP/1.x */
  1947. str_split_char(&p_sess->http_get_arg, &p_sess->ftp_arg_str, ' ');
  1948. str_copy(&p_sess->ftp_arg_str, &p_sess->http_get_arg);
  1949. str_split_char(&p_sess->http_get_arg, &p_sess->ftp_cmd_str, '.');
  1950. str_upper(&p_sess->ftp_cmd_str);
  1951. if (str_equal_text(&p_sess->ftp_cmd_str, "HTML") ||
  1952. str_equal_text(&p_sess->ftp_cmd_str, "HTM"))
  1953. {
  1954. vsf_cmdio_write_raw(p_sess, "Content-Type: text/html\r\n");
  1955. }
  1956. else
  1957. {
  1958. vsf_cmdio_write_raw(p_sess, "Content-Type: dunno\r\n");
  1959. }
  1960. vsf_cmdio_write_raw(p_sess, "\r\n");
  1961. p_sess->is_ascii = 0;
  1962. p_sess->restart_pos = 0;
  1963. handle_retr(p_sess, 1);
  1964. if (vsf_log_entry_pending(p_sess))
  1965. {
  1966. vsf_log_do_log(p_sess, 0);
  1967. }
  1968. vsf_sysutil_exit(0);
  1969. }