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