2 * Part of Very Secure FTPd
7 * Code to parse the FTP protocol prior to a successful login.
16 #include "oneprocess.h"
17 #include "twoprocess.h"
18 #include "sysdeputil.h"
29 static void check_limits(struct vsf_session
* p_sess
);
30 static void emit_greeting(struct vsf_session
* p_sess
);
31 static void parse_username_password(struct vsf_session
* p_sess
);
32 static void handle_user_command(struct vsf_session
* p_sess
);
33 static void handle_pass_command(struct vsf_session
* p_sess
);
34 static void handle_get(struct vsf_session
* p_sess
);
35 static void check_login_delay();
36 static void check_login_fails(struct vsf_session
* p_sess
);
39 init_connection(struct vsf_session
* p_sess
)
41 if (tunable_setproctitle_enable
)
43 vsf_sysutil_setproctitle("not logged in");
45 /* Before we talk to the remote, make sure an alarm is set up in case
46 * writing the initial greetings should block.
48 vsf_cmdio_set_alarm(p_sess
);
49 /* Check limits before doing an implicit SSL handshake, to avoid DoS
50 * attacks. This will result in plain text messages being sent to the SSL
51 * client, but we can live with that.
54 if (tunable_ssl_enable
&& tunable_implicit_ssl
)
56 ssl_control_handshake(p_sess
);
58 if (tunable_ftp_enable
)
60 emit_greeting(p_sess
);
62 parse_username_password(p_sess
);
66 check_limits(struct vsf_session
* p_sess
)
68 struct mystr str_log_line
= INIT_MYSTR
;
69 /* Check for client limits (standalone mode only) */
70 if (tunable_max_clients
> 0 &&
71 p_sess
->num_clients
> tunable_max_clients
)
73 str_alloc_text(&str_log_line
, "Connection refused: too many sessions.");
74 vsf_log_line(p_sess
, kVSFLogEntryConnection
, &str_log_line
);
75 vsf_cmdio_write_exit(p_sess
, FTP_TOO_MANY_USERS
,
76 "There are too many connected users, please try later.");
78 if (tunable_max_per_ip
> 0 &&
79 p_sess
->num_this_ip
> tunable_max_per_ip
)
81 str_alloc_text(&str_log_line
,
82 "Connection refused: too many sessions for this address.");
83 vsf_log_line(p_sess
, kVSFLogEntryConnection
, &str_log_line
);
84 vsf_cmdio_write_exit(p_sess
, FTP_IP_LIMIT
,
85 "There are too many connections from your internet address.");
87 if (!p_sess
->tcp_wrapper_ok
)
89 str_alloc_text(&str_log_line
,
90 "Connection refused: tcp_wrappers denial.");
91 vsf_log_line(p_sess
, kVSFLogEntryConnection
, &str_log_line
);
92 vsf_cmdio_write_exit(p_sess
, FTP_IP_DENY
, "Service not available.");
94 vsf_log_line(p_sess
, kVSFLogEntryConnection
, &str_log_line
);
98 emit_greeting(struct vsf_session
* p_sess
)
100 if (!str_isempty(&p_sess
->banner_str
))
102 vsf_banner_write(p_sess
, &p_sess
->banner_str
, FTP_GREET
);
103 str_free(&p_sess
->banner_str
);
104 vsf_cmdio_write(p_sess
, FTP_GREET
, "");
106 else if (tunable_ftpd_banner
== 0)
108 vsf_cmdio_write(p_sess
, FTP_GREET
, "(vsFTPd " VSF_VERSION
113 vsf_cmdio_write(p_sess
, FTP_GREET
, tunable_ftpd_banner
);
118 parse_username_password(struct vsf_session
* p_sess
)
122 vsf_cmdio_get_cmd_and_arg(p_sess
, &p_sess
->ftp_cmd_str
,
123 &p_sess
->ftp_arg_str
, 1);
124 if (tunable_ftp_enable
)
126 if (str_equal_text(&p_sess
->ftp_cmd_str
, "USER"))
128 handle_user_command(p_sess
);
130 else if (str_equal_text(&p_sess
->ftp_cmd_str
, "PASS"))
132 handle_pass_command(p_sess
);
134 else if (str_equal_text(&p_sess
->ftp_cmd_str
, "QUIT"))
136 vsf_cmdio_write_exit(p_sess
, FTP_GOODBYE
, "Goodbye.");
138 else if (str_equal_text(&p_sess
->ftp_cmd_str
, "FEAT"))
142 else if (str_equal_text(&p_sess
->ftp_cmd_str
, "OPTS"))
146 else if (tunable_ssl_enable
&&
147 str_equal_text(&p_sess
->ftp_cmd_str
, "AUTH") &&
148 !p_sess
->control_use_ssl
)
152 else if (tunable_ssl_enable
&&
153 str_equal_text(&p_sess
->ftp_cmd_str
, "PBSZ"))
157 else if (tunable_ssl_enable
&&
158 str_equal_text(&p_sess
->ftp_cmd_str
, "PROT"))
162 else if (str_isempty(&p_sess
->ftp_cmd_str
) &&
163 str_isempty(&p_sess
->ftp_arg_str
))
165 /* Deliberately ignore to avoid NAT device bugs, as per ProFTPd. */
169 vsf_cmdio_write(p_sess
, FTP_LOGINERR
,
170 "Please login with USER and PASS.");
173 else if (tunable_http_enable
)
175 if (str_equal_text(&p_sess
->ftp_cmd_str
, "GET"))
181 vsf_cmdio_write(p_sess
, FTP_LOGINERR
, "Bad HTTP verb.");
189 handle_get(struct vsf_session
* p_sess
)
192 str_copy(&p_sess
->http_get_arg
, &p_sess
->ftp_arg_str
);
193 str_alloc_text(&p_sess
->user_str
, "FTP");
194 str_alloc_text(&p_sess
->ftp_arg_str
, "<http>");
195 handle_pass_command(p_sess
);
199 handle_user_command(struct vsf_session
* p_sess
)
201 /* SECURITY: If we're in anonymous only-mode, immediately reject
202 * non-anonymous usernames in the hope we save passwords going plaintext
206 str_copy(&p_sess
->user_str
, &p_sess
->ftp_arg_str
);
207 str_upper(&p_sess
->ftp_arg_str
);
208 if (!str_equal_text(&p_sess
->ftp_arg_str
, "FTP") &&
209 !str_equal_text(&p_sess
->ftp_arg_str
, "ANONYMOUS"))
213 if (!tunable_local_enable
&& !is_anon
)
216 p_sess
, FTP_LOGINERR
, "This FTP server is anonymous only.");
217 str_empty(&p_sess
->user_str
);
220 if (is_anon
&& p_sess
->control_use_ssl
&& !tunable_allow_anon_ssl
&&
221 !tunable_force_anon_logins_ssl
)
224 p_sess
, FTP_LOGINERR
, "Anonymous sessions may not use encryption.");
225 str_empty(&p_sess
->user_str
);
228 if (tunable_ssl_enable
&& !is_anon
&& !p_sess
->control_use_ssl
&&
229 tunable_force_local_logins_ssl
)
232 p_sess
, FTP_LOGINERR
, "Non-anonymous sessions must use encryption.");
235 if (tunable_ssl_enable
&& is_anon
&& !p_sess
->control_use_ssl
&&
236 tunable_force_anon_logins_ssl
)
239 p_sess
, FTP_LOGINERR
, "Anonymous sessions must use encryption.");
242 if (tunable_userlist_enable
)
244 int located
= str_contains_line(&p_sess
->userlist_str
, &p_sess
->user_str
);
245 if ((located
&& tunable_userlist_deny
) ||
246 (!located
&& !tunable_userlist_deny
))
249 vsf_cmdio_write(p_sess
, FTP_LOGINERR
, "Permission denied.");
250 check_login_fails(p_sess
);
251 str_empty(&p_sess
->user_str
);
255 if (is_anon
&& tunable_no_anon_password
)
257 /* Fake a password */
258 str_alloc_text(&p_sess
->ftp_arg_str
, "<no password>");
259 handle_pass_command(p_sess
);
263 vsf_cmdio_write(p_sess
, FTP_GIVEPWORD
, "Please specify the password.");
268 handle_pass_command(struct vsf_session
* p_sess
)
270 if (str_isempty(&p_sess
->user_str
))
272 vsf_cmdio_write(p_sess
, FTP_NEEDUSER
, "Login with USER first.");
275 /* These login calls never return if successful */
276 if (tunable_one_process_model
)
278 vsf_one_process_login(p_sess
, &p_sess
->ftp_arg_str
);
282 vsf_two_process_login(p_sess
, &p_sess
->ftp_arg_str
);
284 vsf_cmdio_write(p_sess
, FTP_LOGINERR
, "Login incorrect.");
285 check_login_fails(p_sess
);
286 str_empty(&p_sess
->user_str
);
287 /* FALLTHRU if login fails */
290 static void check_login_delay()
292 if (tunable_delay_failed_login
)
294 vsf_sysutil_sleep((double) tunable_delay_failed_login
);
298 static void check_login_fails(struct vsf_session
* p_sess
)
300 if (++p_sess
->login_fails
>= tunable_max_login_fails
)