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