1/*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 * prelogin.c
6 *
7 * Code to parse the FTP protocol prior to a successful login.
8 */
9
10#include "prelogin.h"
11#include "ftpcmdio.h"
12#include "ftpcodes.h"
13#include "str.h"
14#include "vsftpver.h"
15#include "tunables.h"
16#include "oneprocess.h"
17#include "twoprocess.h"
18#include "sysdeputil.h"
19#include "sysutil.h"
20#include "session.h"
21#include "banner.h"
22#include "logging.h"
23#include "ssl.h"
24#include "features.h"
25
26/* Functions used */
27static void emit_greeting(struct vsf_session* p_sess);
28static void parse_username_password(struct vsf_session* p_sess);
29static void handle_user_command(struct vsf_session* p_sess);
30static void handle_pass_command(struct vsf_session* p_sess);
31
32void
33init_connection(struct vsf_session* p_sess)
34{
35  if (tunable_setproctitle_enable)
36  {
37    vsf_sysutil_setproctitle("not logged in");
38  }
39  /* Before we talk to the remote, make sure an alarm is set up in case
40   * writing the initial greetings should block.
41   */
42  vsf_cmdio_set_alarm(p_sess);
43  emit_greeting(p_sess);
44  parse_username_password(p_sess);
45}
46
47static void
48emit_greeting(struct vsf_session* p_sess)
49{
50  struct mystr str_log_line = INIT_MYSTR;
51  /* Check for client limits (standalone mode only) */
52  if (tunable_max_clients > 0 &&
53      p_sess->num_clients > tunable_max_clients)
54  {
55    str_alloc_text(&str_log_line, "Connection refused: too many sessions.");
56    vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
57    vsf_cmdio_write_exit(p_sess, FTP_TOO_MANY_USERS,
58      "There are too many connected users, please try later.");
59  }
60  if (tunable_max_per_ip > 0 &&
61      p_sess->num_this_ip > tunable_max_per_ip)
62  {
63    str_alloc_text(&str_log_line,
64                   "Connection refused: too many sessions for this address.");
65    vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
66    vsf_cmdio_write_exit(p_sess, FTP_IP_LIMIT,
67      "There are too many connections from your internet address.");
68  }
69  if (!p_sess->tcp_wrapper_ok)
70  {
71    str_alloc_text(&str_log_line,
72                   "Connection refused: tcp_wrappers denial.");
73    vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
74    vsf_cmdio_write_exit(p_sess, FTP_IP_DENY, "Service not available.");
75  }
76  vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
77  if (!str_isempty(&p_sess->banner_str))
78  {
79    vsf_banner_write(p_sess, &p_sess->banner_str, FTP_GREET);
80    str_free(&p_sess->banner_str);
81    vsf_cmdio_write(p_sess, FTP_GREET, "");
82  }
83  else if (tunable_ftpd_banner == 0)
84  {
85    vsf_cmdio_write(p_sess, FTP_GREET, "(vsFTPd " VSF_VERSION
86                    ")");
87  }
88  else
89  {
90    vsf_cmdio_write(p_sess, FTP_GREET, tunable_ftpd_banner);
91  }
92}
93
94static void
95parse_username_password(struct vsf_session* p_sess)
96{
97  while (1)
98  {
99    vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str,
100                              &p_sess->ftp_arg_str, 1);
101    if (str_equal_text(&p_sess->ftp_cmd_str, "USER"))
102    {
103      handle_user_command(p_sess);
104    }
105    else if (str_equal_text(&p_sess->ftp_cmd_str, "PASS"))
106    {
107      handle_pass_command(p_sess);
108    }
109    else if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT"))
110    {
111      vsf_cmdio_write(p_sess, FTP_GOODBYE, "Goodbye.");
112      vsf_sysutil_exit(0);
113    }
114    else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT"))
115    {
116      handle_feat(p_sess);
117    }
118    else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "AUTH"))
119    {
120      handle_auth(p_sess);
121    }
122    else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PBSZ"))
123    {
124      handle_pbsz(p_sess);
125    }
126    else if (tunable_ssl_enable && str_equal_text(&p_sess->ftp_cmd_str, "PROT"))
127    {
128      handle_prot(p_sess);
129    }
130    else
131    {
132      vsf_cmdio_write(p_sess, FTP_LOGINERR,
133                      "Please login with USER and PASS.");
134    }
135  }
136}
137
138static void
139handle_user_command(struct vsf_session* p_sess)
140{
141  /* SECURITY: If we're in anonymous only-mode, immediately reject
142   * non-anonymous usernames in the hope we save passwords going plaintext
143   * over the network
144   */
145  int is_anon = 1;
146  str_copy(&p_sess->user_str, &p_sess->ftp_arg_str);
147  str_upper(&p_sess->ftp_arg_str);
148  if (
149//  	!str_equal_text(&p_sess->ftp_arg_str, "FTP") &&	// Jiahao
150      !str_equal_text(&p_sess->ftp_arg_str, "ANONYMOUS")
151     )
152  {
153    is_anon = 0;
154  }
155  if (!tunable_local_enable && !is_anon)
156  {
157    vsf_cmdio_write(
158      p_sess, FTP_LOGINERR, "This FTP server is anonymous only.");
159    str_empty(&p_sess->user_str);
160    return;
161  }
162  if (!tunable_anonymous_enable && is_anon)
163  {
164    vsf_cmdio_write(
165      p_sess, FTP_LOGINERR, "This FTP server does not allow anonymous logins.");
166  }
167  if (is_anon && p_sess->control_use_ssl && !tunable_allow_anon_ssl &&
168      !tunable_force_anon_logins_ssl)
169  {
170    vsf_cmdio_write(
171      p_sess, FTP_LOGINERR, "Anonymous sessions may not use encryption.");
172    str_empty(&p_sess->user_str);
173    return;
174  }
175  if (tunable_ssl_enable && !is_anon && !p_sess->control_use_ssl &&
176      tunable_force_local_logins_ssl)
177  {
178    vsf_cmdio_write(
179      p_sess, FTP_LOGINERR, "Non-anonymous sessions must use encryption.");
180    str_empty(&p_sess->user_str);
181    return;
182  }
183  if (tunable_ssl_enable && is_anon && !p_sess->control_use_ssl &&
184      tunable_force_anon_logins_ssl)
185  {
186    vsf_cmdio_write(
187      p_sess, FTP_LOGINERR, "Anonymous sessions must use encryption.");
188    str_empty(&p_sess->user_str);
189    return;
190  }
191  if (!str_isempty(&p_sess->userlist_str))
192  {
193    int located = str_contains_line(&p_sess->userlist_str, &p_sess->user_str);
194    if ((located && tunable_userlist_deny) ||
195        (!located && !tunable_userlist_deny))
196    {
197      vsf_cmdio_write(p_sess, FTP_LOGINERR, "Permission denied.");
198      str_empty(&p_sess->user_str);
199      return;
200    }
201  }
202
203  if (str_equal_text(&p_sess->ftp_arg_str, "ROOT")) // Modify by Jiahao 2006.10.20
204  {
205    vsf_cmdio_write(p_sess, FTP_LOGINERR, "Permission denied.");
206    str_empty(&p_sess->user_str);
207    return;
208  }
209
210  if (is_anon && tunable_no_anon_password)
211  {
212    /* Fake a password */
213    str_alloc_text(&p_sess->ftp_arg_str, "<no password>");
214    handle_pass_command(p_sess);
215  }
216  else
217  {
218    vsf_cmdio_write(p_sess, FTP_GIVEPWORD, "Please specify the password.");
219  }
220}
221
222static void
223handle_pass_command(struct vsf_session* p_sess)
224{
225  if (str_isempty(&p_sess->user_str))
226  {
227    vsf_cmdio_write(p_sess, FTP_NEEDUSER, "Login with USER first.");
228    return;
229  }
230  /* These login calls never return if successful */
231  if (tunable_one_process_model)
232  {
233    vsf_one_process_login(p_sess, &p_sess->ftp_arg_str);
234  }
235  else
236  {
237    vsf_two_process_login(p_sess, &p_sess->ftp_arg_str);
238  }
239  vsf_cmdio_write(p_sess, FTP_LOGINERR, "Login incorrect.");
240  str_empty(&p_sess->user_str);
241  /* FALLTHRU if login fails */
242}
243
244