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