/** *do_mkd - 创建目录 *@sess:会话结构体 */ void ftpproto::do_mkd(session_t* sess) { if (mkdir(sess->arg,0777) < 0)//0777为权限 0777&umask {//创建目录失败(没有写入权限时好像也可以写入) ftp_reply(sess,FTP_FILEFAIL,"Create directory operation failed.");//响应 return; } char text[4096] = {0}; if (sess->arg[0] == '/')//如果是绝对路径 { sprintf(text,"%s created.",sess->arg); } else//是相对路径 { char dir[4096+1] = {0}; //获取当前路径 getcwd(dir,4096); if (dir[strlen(dir) - 1] == '/')//最后一个字符是否等于斜杠 { sprintf(text,"%s%s created.",dir,sess->arg); } else { sprintf(text,"%s/%s created.",dir,sess->arg); } } ftp_reply(sess,FTP_MKDIROK,text);//响应 }
void do_cmd_mkd(session_t *pses) { if(mkdir(pses->arg, 0777) < 0) { ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Create directory operation failed."); return; } char sendbuf[PATH_MAX + 1] = {0}; if(pses->arg[0] == '/') { //绝对路径 sprintf(sendbuf, "\"%s\" created.",pses->arg); } else { //相对路径 char dir[PATH_MAX + 1] = {0}; getcwd(dir, PATH_MAX); if(dir[strlen(dir) - 1] != '/') { dir[strlen(dir) - 1] = '/'; dir[strlen(dir)] = '\0'; } sprintf(sendbuf, "\"%s%s\" created.", dir,pses->arg); } ftp_reply(pses->ctrl_fd, FTP_MKDIROK, sendbuf); }
static void do_mkd(session_t *sess) { if(mkdir(sess->arg, 0777) < 0) { ftp_reply(sess, FTP_FILEFAIL, "Create directory operation failed."); return; } char text[1024] = {0}; if(sess->arg[0] == '/') sprintf(text, "%s created", sess->arg); else { char dir[1024 + 1] = {0}; getcwd(dir, 1024); if(dir[strlen(dir) - 1] == '/') sprintf(text, "%s%s created", dir, sess->arg); else sprintf(text, "%s/%s created", dir, sess->arg); } ftp_reply(sess, FTP_MKDIROK, text); }
void do_site_chmod(session_t *sess, char *args) { if (strlen(args) == 0) { ftp_reply(sess, FTP_BADCMD, "SITE CHMOD needs 2 arguments."); return; } char perm[100] = {0}; char file[100] = {0}; str_split(args , perm, file, ' '); if (strlen(file) == 0) { ftp_reply(sess, FTP_BADCMD, "SITE CHMOD needs 2 arguments."); return; } unsigned int mode = str_octal_to_uint(perm); if (chmod(file, mode) < 0) { ftp_reply(sess, FTP_CHMODOK, "SITE CHMOD command failed."); } else { ftp_reply(sess, FTP_CHMODOK, "SITE CHMOD command ok."); } }
static void do_pass(session_t* sess) { struct passwd* pw = getpwuid(sess->uid); if(pw == NULL) { ftp_reply(sess, FTP_LOGINERR, "Login incorrect."); return; } struct spwd* sp = getspnam(pw->pw_name); if(sp == NULL) { ftp_reply(sess, FTP_LOGINERR, "Login incorrect."); return; } char* encrypted_pass = crypt(sess->arg, sp->sp_pwdp); if(strcmp(encrypted_pass, sp->sp_pwdp) != 0) { ftp_reply(sess, FTP_LOGINERR, "Login incorrect."); return; } signal(SIGURG, handle_sigurg); activate_sigurg(sess->ctrl_fd); //change to login user setegid(pw->pw_gid); seteuid(pw->pw_uid); chdir(pw->pw_dir); umask(tunable_local_umask); ftp_reply(sess, FTP_LOGINOK, "Login successful."); }
static void do_cdup(session_t *sess) { if(chdir("..") < 0) { ftp_reply(sess, FTP_FILEFAIL, "Failed to change directory."); return; } ftp_reply(sess, FTP_CWDOK, "Directory successful changed."); }
/** *handle_ftp - ftp服务进程的处理函数 *@sess:会话结构体 *主要完成从ftp客户端读取命令,解析并调用响应函数执行 */ void ftpproto::handle_ftp(session_t* sess) { LCWFTPD_LOG(DEBUG,"Hello handle_ftp"); ftp_reply(sess,FTP_GREET,"(lcwftpd 1.0 welcome you!!!by LinChuangwei.)"); ftp_commands_map_init();//初始化map LCWFTPD_LOG(DEBUG,"All supported commands:"); for(it = commandsmap.begin();it != commandsmap.end();it++) { std::cout << it->first <<" "; } std::cout << std::endl; while(1) { //三个保存命令的数组清空 memset(sess->cmdline,0,sizeof(sess->cmdline)); memset(sess->cmd,0,sizeof(sess->cmd)); memset(sess->arg,0,sizeof(sess->arg)); //读取命令到cmdline ret = lcw_systools.readline(sess->ctrl_fd,sess->cmdline,MAX_COMMAND); LCWFTPD_LOG(DEBUG,"ctrl_fd:%d",sess->ctrl_fd); LCWFTPD_LOG(DEBUG,"ret:%d",ret); if (-1 == ret)//读取错误 { LCWFTPD_LOG(ERROR,"lcw_systools.readline"); } else if (0 == ret)//等于0表示断开了连接 { LCWFTPD_LOG(ERROR,"client %s disconnect",sess->ip); } //USER scut_lcw\r\n 空格前面看成命令,之后看成参数 //首先要去除/r/n lcw_ftpstr.str_trim_crlf(sess->cmdline); LCWFTPD_LOG(DEBUG,"cmdline:%s",sess->cmdline); //根据空格分割字符串 lcw_ftpstr.str_split(sess->cmdline,sess->cmd,sess->arg,' '); //将命令转换为大写 lcw_ftpstr.str_upper(sess->cmd); LCWFTPD_LOG(DEBUG,"cmd:%s",sess->cmd); LCWFTPD_LOG(DEBUG,"arg:%s",sess->arg); it = commandsmap.find(sess->cmd);//根据命令查找相应的执行函数 if (it != commandsmap.end()) {//存在和命令相对应的函数 // LCWFTPD_LOG(DEBUG,"执行命令"); (this->*(it->second))(sess);//执行命令 } else { // LCWFTPD_LOG(DEBUG,"没有执行命令"); // 500 ftp_reply(sess,FTP_BADCMD,"Sorry! Unknown command"); } } }
static void do_rmd(session_t *sess) { if(rmdir(sess->arg) < 0) { ftp_reply(sess, FTP_FILEFAIL, "Remove directory operation failed."); return; } ftp_reply(sess, FTP_RMDIROK, "Delete operation successful."); }
void do_cmd_dele(session_t *pses) { if(unlink(pses->arg) < 0) { ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Delete operation failed."); return; } ftp_reply(pses->ctrl_fd, FTP_DELEOK, "Delete operation successful."); }
void do_cmd_rmd(session_t *pses) { if(rmdir(pses->arg) < 0) { ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Remove directory operation failed."); return; } ftp_reply(pses->ctrl_fd, FTP_RMDIROK, "Remove directory operation successful."); }
static void do_dele(session_t *sess) { if(unlink(sess->arg) < 0) { ftp_reply(sess, FTP_FILEFAIL, "Delete operation failed."); return; } ftp_reply(sess, FTP_DELEOK, "Delete operation successful."); }
void do_cmd_cdup(session_t *pses) { if(chdir("..") < 0) { ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Failed to change directory."); return; } ftp_reply(pses->ctrl_fd, FTP_CWDOK, "Directory successfully changed."); }
void handle_child(session_t *pses) { if(pses == NULL) handle_error_str("do_cmd_user: pses is NULL."); ftp_reply(pses->ctrl_fd, FTP_GREET, "(Mftp 0.1)"); //220 int iret; while(true) { memset(pses->cmdline, 0, MAX_COMMAND_LINE); memset(pses->cmd, 0, MAX_COMMAND); memset(pses->arg, 0, MAX_ARG); iret = recvline(pses->ctrl_fd, pses->cmdline, MAX_COMMAND_LINE);//接收命令行 if(iret == -1) handle_error("recvline"); else if(iret == 0) handle_error("recvline"); //去掉\r\n str_trim_crlf(pses->cmdline); //分割命令和参数 str_split(pses->cmdline, pses->cmd, pses->arg, ' '); //将命令转换成大写 str_upper(pses->cmd); #ifdef _DEBUG_ printf("cmd = [%s] arg = [%s]\n", pses->cmd,pses->arg); #endif //处理ftp命令 int len = ARRAYLEN(ctrl_cmds); int i = 0; for(i = 0; i < len; i++) { if(strcmp(ctrl_cmds[i].cmd, pses->cmd) == 0) { if(ctrl_cmds[i].cmd_handler != NULL) { (*ctrl_cmds[i].cmd_handler)(pses); //等价于ctrl_cmds[i].cmd_handler(pses); } else { ftp_reply(pses->ctrl_fd, FTP_COMMANDNOTIMPL, "Unimplement command."); //502 } break; } } if(i >= len) { //没找到命令 ftp_reply(pses->ctrl_fd, FTP_BADCMD, "Unknown command."); } } }
/** *do_dele - 删除文件 *@sess:会话结构体 */ void ftpproto::do_dele(session_t* sess) { //使用unlink删除文件 if (unlink(sess->arg) < 0) { ftp_reply(sess,FTP_FILEFAIL,"Delete operation failed."); return; } ftp_reply(sess,FTP_DELEOK,"Delete operation successful."); }
/** *do_cdup - 返回上层目录 *@sess:会话结构体 */ void ftpproto::do_cdup(session_t* sess) { //更改到上层路径 if (chdir("..") < 0)//这里好像也是可以切换到root的???? {//更改路径失败 ftp_reply(sess,FTP_FILEFAIL,"Failed to change directory."); return; } ftp_reply(sess,FTP_CWDOK,"Directory successful changed."); }
/** *do_cwd - 改变当前路径 *@sess:会话结构体 */ void ftpproto::do_cwd(session_t* sess) { //更改路径,此时路径已经存放于arg中 if (chdir(sess->arg) < 0)//这里好像也是可以切换到root的???? {//更改路径失败 ftp_reply(sess,FTP_FILEFAIL,"Failed to change directory."); return; } ftp_reply(sess,FTP_CWDOK,"Directory successful changed."); }
void limit_num_clients(session_t *sess) { if (max_clients > 0 && sess->curr_clients > max_clients) { ftp_reply(sess, FTP_TOO_MANY_USERS, "There are too many users, please try again later"); exit(EXIT_FAILURE); } if (max_per_ip > 0 && sess->curr_ip_clients > max_per_ip) { ftp_reply(sess, FTP_IP_LIMIT, "There are too many connections from your ip."); exit(EXIT_FAILURE); } }
static void do_user(session_t* sess) { struct passwd* pw = getpwnam(sess->arg); if(pw == NULL) { ftp_reply(sess, FTP_LOGINERR, "Login incorrect."); return; } sess->uid = pw->pw_uid; ftp_reply(sess, FTP_GIVEPWORD, "Please specify the password."); }
static void do_nlst(session_t *sess) { if(get_transfer_fd(sess) == 0) return; ftp_reply(sess, FTP_DATACONN, "Here comes the directory listing."); list_common(sess, 0); close(sess->data_fd); sess->data_fd = -1; ftp_reply(sess, FTP_TRANSFEROK, "Directory send OK."); }
static void do_rnto(session_t *sess) { if(sess->rnfr_name == NULL) { ftp_reply(sess, FTP_NEEDRNFR, "RNFR required first."); return; } rename(sess->rnfr_name, sess->arg); ftp_reply(sess, FTP_RENAMEOK, "Rename successful."); free(sess->rnfr_name); sess->rnfr_name = NULL; }
/** *do_user - 发送用户命令以供登陆 *@sess:会话结构体 */ void ftpproto::do_user(session_t* sess) { LCWFTPD_LOG(DEBUG,"do_user"); //USER scut_lcw struct passwd* pw = getpwnam(sess->arg);//根据用户名获取登陆相关的结构体 if (pw == NULL)//用户不存在 { ftp_reply(sess,FTP_LOGINERR,"Oh no~Login incorrect."); return; } sess->uid = pw->pw_uid;//保存用户id //331 ftp_reply(sess,FTP_GIVEPWORD,"Hi~Please specify the password."); }
/** *do_rnto - 文件重命名,在rnfr后接收到,改后的文件名 *@sess:会话结构体 */ void ftpproto::do_rnto(session_t* sess) { if (sess->rnfr_name == NULL) { //之前没有收到过RNFR命令 ftp_reply(sess,FTP_NEEDRNFR,"RNFR required first."); return; } //arg保存的是改后的文件名 rename(sess->rnfr_name,sess->arg);//重命名 ftp_reply(sess,FTP_RENAMEOK,"Rename successful."); free(sess->rnfr_name);//释放内存 sess->rnfr_name = NULL; }
//获取目录详细清单 void do_cmd_list(session_t *pses) { //创建数据连接 if(get_transfer_fd(pses) < 0) return; //150 ftp_reply(pses->ctrl_fd, FTP_DATACONN, "Here comes the directory listing."); //传输列表 getdirlist(pses,1); //关闭数据套接字 close(pses->data_fd); pses->data_fd = -1; //226 ftp_reply(pses->ctrl_fd, FTP_TRANSFEROK, "Directory send OK."); }
void check_clients_limit(session_t* sess) { if (tunable_max_clients > 0 && sess->num_clients > tunable_max_clients) { ftp_reply(sess, FTP_TOO_MANY_USERS, "There are too many connected users, Please try later."); exit(EXIT_FAILURE); } if (tunable_max_per_ip > 0 && sess->num_this_ip > tunable_max_per_ip) { ftp_reply(sess, FTP_TOO_MANY_USERS, "There are too many connections from your internet address, Please try later."); exit(EXIT_FAILURE); } }
void do_cmd_pass(session_t *pses) { if(pses == NULL) handle_error_str("do_cmd_user: pses is NULL."); //收到密码后,开始用户验证 //根据用户uid获取用户信息 struct passwd *pw = getpwuid(pses->uid); //尝试获取要登陆用户的信息 if(pw == NULL) { //用户不存在 ftp_reply(pses->ctrl_fd, FTP_LOGINERR, "Login incorrect."); //530 return; } //根据用户名字获取密码信息 struct spwd *sp = getspnam(pw->pw_name); if(sp == NULL) { //用户不存在 ftp_reply(pses->ctrl_fd, FTP_LOGINERR, "Login incorrect."); //530 return; } //将明文密码进行加密 struct crypt_data data; data.initialized = 0; char *encrupted_pass = crypt_r(pses->arg, sp->sp_pwdp,&data); //加密结果对比 if(strcmp(encrupted_pass, sp->sp_pwdp) != 0) { //验证失败 ftp_reply(pses->ctrl_fd, FTP_LOGINERR, "Login incorrect."); //530 return; } //密码验证成功 ftp_reply(pses->ctrl_fd, FTP_LOGINOK, "Login successful."); //230 //更改umask umask(tunable_local_umask); //更改进程属性 if(setegid(pw->pw_gid) < 0) handle_error("setegid"); if(seteuid(pw->pw_uid) < 0) handle_error("seteuid"); //更改当前工作目录到用户家目录 if(chdir(pw->pw_dir) < 0) handle_error("chdir"); }
/** *do_rnfr - 文件重命名,先发送的是rnfr,要重命名的文件名 *@sess:会话结构体 */ void ftpproto::do_rnfr(session_t* sess) {//保存要重命名的文件名 sess->rnfr_name = (char*)malloc(strlen(sess->arg) + 1); memset(sess->rnfr_name,0,strlen(sess->arg) + 1); memcpy(sess->rnfr_name,sess->arg,strlen(sess->arg) + 1); ftp_reply(sess,FTP_RNFROK,"Ready for RNTO."); }
static void do_rnfr(session_t *sess) { sess->rnfr_name = (char*)malloc(strlen(sess->arg) + 1); memset(sess->rnfr_name, 0, strlen(sess->arg) + 1); strcpy(sess->rnfr_name, sess->arg); ftp_reply(sess, FTP_RNFROK, "Ready for RNTO."); }
static void do_list(session_t *sess) { if(get_transfer_fd(sess) == 0) return; ftp_reply(sess, FTP_DATACONN, "Here comes the directory listing."); //transfer list list_common(sess, 1); //client will still wait the data from server if the fd do not closed close(sess->data_fd); sess->data_fd = -1; ftp_reply(sess, FTP_TRANSFEROK, "Directory send OK."); }
int get_transfer_fd(session_t* sess) { //check have received port or pasv command before if(!port_active(sess) && !pasv_active(sess)) { ftp_reply(sess, FTP_BADSENDCONN, "Use PORT or PASV first."); return 0; } int ret = 1; if(port_active(sess)) { if(get_port_fd(sess) == 0) ret = 0; } if(pasv_active(sess)) { if(get_pasv_fd(sess) == 0) ret = 0; } if(sess->port_addr) { free(sess->port_addr); sess->port_addr = NULL; } if(ret) start_data_alarm(); return ret; }
void handle_alarm_timeout(int aig) { shutdown(p_sess->ctrl_fd, SHUT_RD); ftp_reply(p_sess, FTP_IDLE_TIMEOUT, "Timeout."); shutdown(p_sess->ctrl_fd, SHUT_WR); exit(EXIT_FAILURE); }