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