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 * License: GPL v2 20 * Author: Chris Evans 21 * privops.c 22 * 23 * Code implementing the privileged operations that the unprivileged client 24 * might request. 25 * Look for suitable paranoia in this file. 26 */ 27 28#include "privops.h" 29#include "session.h" 30#include "sysdeputil.h" 31#include "sysutil.h" 32#include "utility.h" 33#include "str.h" 34#include "tunables.h" 35#include "defs.h" 36#include "logging.h" 37#include <string.h> 38#include <stdlib.h> 39#include <stdio.h> 40#include <bcmnvram.h> 41 42/* File private functions */ 43static enum EVSFPrivopLoginResult handle_anonymous_login( 44 struct vsf_session* p_sess, const struct mystr* p_pass_str); 45static enum EVSFPrivopLoginResult handle_local_login( 46 struct vsf_session* p_sess, const struct mystr* p_user_str, 47 const struct mystr* p_pass_str); 48static void setup_username_globals(struct vsf_session* p_sess, 49 const struct mystr* p_str); 50static enum EVSFPrivopLoginResult handle_login( 51 struct vsf_session* p_sess, const struct mystr* p_user_str, 52 const struct mystr* p_pass_str); 53 54int 55vsf_privop_get_ftp_port_sock(struct vsf_session* p_sess) 56{ 57 static struct vsf_sysutil_sockaddr* p_sockaddr; 58 int retval; 59 int s = vsf_sysutil_get_ipsock(p_sess->p_local_addr); 60 vsf_sysutil_activate_reuseaddr(s); 61 vsf_sysutil_sockaddr_clone(&p_sockaddr, p_sess->p_local_addr); 62 vsf_sysutil_sockaddr_set_port(p_sockaddr, tunable_ftp_data_port); 63 retval = vsf_sysutil_bind(s, p_sockaddr); 64 if (retval != 0) 65 { 66 die("vsf_sysutil_bind"); 67 } 68 return s; 69} 70 71void 72vsf_privop_do_file_chown(struct vsf_session* p_sess, int fd) 73{ 74 static struct vsf_sysutil_statbuf* s_p_statbuf; 75 vsf_sysutil_fstat(fd, &s_p_statbuf); 76 /* Do nothing if it is already owned by the desired user. */ 77 if (vsf_sysutil_statbuf_get_uid(s_p_statbuf) == 78 p_sess->anon_upload_chown_uid) 79 { 80 return; 81 } 82 /* Drop it like a hot potato unless it's a regular file owned by 83 * the the anonymous ftp user 84 */ 85 if (p_sess->anon_upload_chown_uid == -1 || 86 !vsf_sysutil_statbuf_is_regfile(s_p_statbuf) || 87 (vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->anon_ftp_uid && 88 vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->guest_user_uid)) 89 { 90 die("invalid fd in cmd_process_chown"); 91 } 92 /* SECURITY! You need an OS which strips SUID/SGID bits on chown(), 93 * otherwise a compromise of the FTP user will lead to compromise of 94 * the "anon_upload_chown_uid" user (think chmod +s). 95 */ 96 vsf_sysutil_fchown(fd, p_sess->anon_upload_chown_uid, -1); 97} 98 99enum EVSFPrivopLoginResult 100vsf_privop_do_login(struct vsf_session* p_sess, 101 const struct mystr* p_pass_str) 102{ 103 enum EVSFPrivopLoginResult result = 104 handle_login(p_sess, &p_sess->user_str, p_pass_str); 105 vsf_log_start_entry(p_sess, kVSFLogEntryLogin); 106 if (result == kVSFLoginFail) 107 { 108 vsf_log_do_log(p_sess, 0); 109 } 110 else 111 { 112 vsf_log_do_log(p_sess, 1); 113 } 114 return result; 115} 116 117static enum EVSFPrivopLoginResult 118handle_login(struct vsf_session* p_sess, const struct mystr* p_user_str, 119 const struct mystr* p_pass_str) 120{ 121 /* Do not assume PAM can cope with dodgy input, even though it 122 * almost certainly can. 123 */ 124 int anonymous_login = 0; 125 unsigned int len = str_getlen(p_user_str); 126 if (len == 0 || len > VSFTP_USERNAME_MAX) 127 { 128 return kVSFLoginFail; 129 } 130 /* Throw out dodgy start characters */ 131 if (!vsf_sysutil_isalnum(str_get_char_at(p_user_str, 0))) 132 { 133 return kVSFLoginFail; 134 } 135 /* Throw out non-printable characters and space in username */ 136 if (str_contains_space(p_user_str) || 137 str_contains_unprintable(p_user_str)) 138 { 139 return kVSFLoginFail; 140 } 141 /* Throw out excessive length passwords */ 142 len = str_getlen(p_pass_str); 143 if (len > VSFTP_PASSWORD_MAX) 144 { 145 return kVSFLoginFail; 146 } 147 /* Check for an anonymous login or "real" login */ 148 if (tunable_anonymous_enable) 149 { 150 struct mystr upper_str = INIT_MYSTR; 151 str_copy(&upper_str, p_user_str); 152 str_upper(&upper_str); 153 if ( 154// str_equal_text(&upper_str, "FTP") || // Jiahao 155 str_equal_text(&upper_str, "ANONYMOUS") 156 ) 157 { 158 anonymous_login = 1; 159 } 160 str_free(&upper_str); 161 } 162 { 163 enum EVSFPrivopLoginResult result = kVSFLoginFail; 164 if (anonymous_login) 165 { 166 result = handle_anonymous_login(p_sess, p_pass_str); 167 } 168 else 169 { 170 result = handle_local_login(p_sess, p_user_str, p_pass_str); 171 } 172 return result; 173 } 174} 175 176static enum EVSFPrivopLoginResult 177handle_anonymous_login(struct vsf_session* p_sess, 178 const struct mystr* p_pass_str) 179{ 180 if (!str_isempty(&p_sess->banned_email_str) && 181 str_contains_line(&p_sess->banned_email_str, p_pass_str)) 182 { 183 return kVSFLoginFail; 184 } 185 if (!str_isempty(&p_sess->email_passwords_str) && 186 (!str_contains_line(&p_sess->email_passwords_str, p_pass_str) || 187 str_isempty(p_pass_str))) 188 { 189 return kVSFLoginFail; 190 } 191 /* Store the anonymous identity string */ 192 str_copy(&p_sess->anon_pass_str, p_pass_str); 193 if (str_isempty(&p_sess->anon_pass_str)) 194 { 195 str_alloc_text(&p_sess->anon_pass_str, "?"); 196 } 197 /* "Fix" any characters which might upset the log processing */ 198 str_replace_char(&p_sess->anon_pass_str, ' ', '_'); 199 str_replace_char(&p_sess->anon_pass_str, '\n', '?'); 200 { 201 struct mystr ftp_username_str = INIT_MYSTR; 202 str_alloc_text(&ftp_username_str, tunable_ftp_username); 203 setup_username_globals(p_sess, &ftp_username_str); 204 str_free(&ftp_username_str); 205 } 206 str_free(&p_sess->banned_email_str); 207 str_free(&p_sess->email_passwords_str); 208 return kVSFLoginAnon; 209} 210 211static enum EVSFPrivopLoginResult 212handle_local_login(struct vsf_session* p_sess, 213 const struct mystr* p_user_str, 214 const struct mystr* p_pass_str) 215{ 216 if (!vsf_sysdep_check_auth(p_user_str, p_pass_str, &p_sess->remote_ip_str)) 217 { 218 return kVSFLoginFail; 219 } 220 setup_username_globals(p_sess, p_user_str); 221 return kVSFLoginReal; 222} 223 224static void 225setup_username_globals(struct vsf_session* p_sess, const struct mystr* p_str) 226{ 227// 2007.08 James { 228 //int snum, unum, i, j; 229 //char user[64], user1[64], wright[384], tmpstr[64]; 230// 2007.08 James } 231 232 str_copy(&p_sess->user_str, p_str); 233 if (tunable_setproctitle_enable) 234 { 235 struct mystr prefix_str = INIT_MYSTR; 236 str_copy(&prefix_str, &p_sess->remote_ip_str); 237 str_append_char(&prefix_str, '/'); 238 str_append_str(&prefix_str, p_str); 239 vsf_sysutil_set_proctitle_prefix(&prefix_str); 240 str_free(&prefix_str); 241 } 242 243// 2007.08 James { 244 p_sess->write_enable = 1; 245 /*char cwdpath[VSFTP_PATH_MAX]; 246 vsf_sysutil_getcwd(cwdpath, VSFTP_PATH_MAX); 247 248 if (nvram_match("st_ftp_mode", "1")) 249 { 250 p_sess->write_enable = 1; 251 return; 252 } 253 254 unum = atoi(nvram_safe_get("acc_num")); 255 for(i=-1;i<unum;i++) 256 { 257 if (i==-1) 258 { 259 strcpy(user, "Guest"); 260 strcpy(user1, "anonymous"); 261 } 262 else 263 { 264 sprintf(tmpstr, "acc_username%d", i); 265 strcpy(user, nvram_safe_get(tmpstr)); 266 strcpy(user1, user); 267 } 268 269 if(strcmp(str_getbuf(p_str), user1)==0) 270 { 271 snum = atoi(nvram_safe_get("sh_num")); 272 273 for(j=0;j<snum;j++) 274 { 275 sprintf(tmpstr, "sh_wright%d", j); 276 strcpy(wright, nvram_safe_get(tmpstr)); 277 278 if (test_user(wright, user)==1) 279 { 280 p_sess->write_enable = 1; 281 return; 282 } 283 } 284 285 p_sess->write_enable = 0; 286 return; 287 } 288 } 289 290 p_sess->write_enable = 0;*/ 291// 2007.08 James } 292 return; 293 294} 295 296