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