⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpcmd.c

📁 模拟linux平台下边的vsFtp服务器可以实现文件的断点续传和下载
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>

#include "ftpcmd.h"
#include "ftppub.h"
#include "ftpnet.h"
#include "ftpdatatrans.h"



FTPCMD cmd_list[] = {
	{"USER",	do_user,	CHECK_NOLOGIN | NEED_PARAM	},
	{"PASS",	do_pass,	CHECK_NOLOGIN				},
	{"CWD",		do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"XCWD",	do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"CDUP",	do_cdup,	CHECK_LOGIN | NO_PARAM		},
	{"XCUP",	do_cdup,	CHECK_LOGIN | NO_PARAM		},
	{"SYST",    do_syst,	CHECK_LOGIN					},
	{"PWD",     do_pwd,		CHECK_LOGIN | NO_PARAM		},
	{"XPWD",    do_pwd,		CHECK_LOGIN | NO_PARAM		},
	{"TYPE",    do_type,	CHECK_LOGIN | NEED_PARAM	},
	{"PORT",    do_port,	CHECK_LOGIN | NEED_PARAM	},
	{"LIST",    do_list,	CHECK_LOGIN					},
	{"NLST",    do_nlst,	CHECK_LOGIN					},
	{"CWD",     do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"XCWD",	do_cwd,		CHECK_LOGIN | NEED_PARAM	},
	{"CDUP",    do_cdup,	CHECK_LOGIN | NO_PARAM		},
	{"RMD",     do_rmd,		CHECK_LOGIN | NEED_PARAM	},
	{"XRMD",    do_rmd,		CHECK_LOGIN | NEED_PARAM	},
	{"MKD",     do_mkd,		CHECK_LOGIN | NEED_PARAM	},
	{"XMKD",    do_mkd,		CHECK_LOGIN | NEED_PARAM	},
	{"DELE",    do_dele,	CHECK_LOGIN | NEED_PARAM	},
	
	
	{"REIN",    do_rein,	CHECK_LOGIN					},
	{"HELP",    do_help,	CHECK_LOGIN					},
	{"QUIT",    do_quit,	NO_CHECK					},
	{"REST",    do_rest,	CHECK_LOGIN | NEED_PARAM	},
	{"PASV",    do_pasv,	CHECK_LOGIN | NO_PARAM		},
	{"RNFR",    do_rnfr,	CHECK_LOGIN | NEED_PARAM	},
	{"RNTO",    do_rnto,	CHECK_LOGIN | NEED_PARAM	},
	{"SIZE",    do_size,	CHECK_LOGIN | NEED_PARAM	},
	{"NOOP",    do_noop,	NO_CHECK					},
	{"STOR",    do_stor,	CHECK_LOGIN | NEED_PARAM	},
	{"RETR",    do_retr,	CHECK_LOGIN | NEED_PARAM	},
	{"APPE",    do_appe,	CHECK_LOGIN | NEED_PARAM	},
	{"ABOR",    do_abor,	CHECK_LOGIN | NO_PARAM		},

	{"ACCT",	NULL									},
    {"SMNT",	NULL									},
    {"STRU",	NULL									},
    {"MODE",	do_mode,								},
    {"STOU",	NULL									},
    {"ALLO",	NULL									},
    {"MDTM",    NULL,   CHECK_LOGIN | NEED_PARAM		},
    {"SITE",    NULL,   CHECK_LOGIN | NEED_PARAM		},
    {"STAT",    do_stat,   CHECK_LOGIN | NEED_PARAM		},
	{""}
};


int do_user(char *param)
{
	if(userlogined==1)
	{
		Respond(500,"User is logined");
		return -1;
	}
	char buff[PARAM_BUFF_SIZE]={0};//命 令参数缓冲区
	int i=0;
	Intercept_Parameter(buff,param);
	//printf("%s\n",buff);
	strcpy(userName,buff);
	//将存放在临时变量中的用户名全转小写
	for(;i<strlen(buff);i++)
	{
		userName[i]=tolower(userName[i]);
	}
	//判断用户是否为匿名用户
	if(strcmp(userName,"anonymous")==0)
	{
	//	printf("匿名用户登 入\n");
		IsAnonymous=1;
		strcpy(userName,"ftp");
	}
	Respond(331,"Please specify the password");
	return 1;
}
int do_pass(char *param)
{
	int state;//保存login返回值	
	char password[100]={0};
	Intercept_Parameter(password,param);//取出密户端传送过来的密码
//	printf("IsAnonymous 值为%d\n",IsAnonymous);
	if(IsAnonymous==1) //匿名用户登入
	{
		//state=1;
//		printf("匿名登入\n");
//		printf("匿名登入的用户名为 %s \n",userName);
		state=Anonymous_Login(userName,password);
//		printf("匿名登入成功 Anonymous_Login函数返回值为%d\n",state);
	}
	else  //正常用户登 入
	{
		state=Login(userName,password);
		//printf("%d \n",state);
//		printf("用户名为 %s,密码%s \n",userName,password);
	}
	if(state>0)//成功登入的情况
	{
		userlogined=1;//用户登入
		Respond(230,"Please specify the password");
	}
	else
	{
		Respond(530,"User name or Password Error");
	}
	

	return 1;
}

/*
int do_cwd(char *param)
{
	char buf[512]={0};
	int stat=0;
	Intercept_Parameter(buf,param);//分离出参数
	if(IsAnonymous==1)//即匿名用户登入
	{

	}
	else
	{
		char curpath[1024]={0};
		getcwd(curpath,1024);
//		printf("CWD命令中执行chdir前的当前路径是: %s\n",curpath);
		stat=chdir(buf);
		memset(curpath,0,sizeof(curpath));
		getcwd(curpath,1024);
//		printf("CWD命令中执行chdir后的当前路径是: %s\n",curpath);

		if(stat==0)
		{
			if(buf[0]=='/') //以'/'开头的路径
			{
				strcpy(path,buf);
			}
			else
			{
				if( path[strlen(path)-1]!='/' ) //判断当前路径是否以'/'结尾
				{
					strcat(path,"/");//在路径后补一个'/'
					strcat(path,buf);//然后再加上目录名
				}
				else
				{
					strcat(path,buf);
				}
			}
		}
	}
	
	if(stat==0)
	{
		Respond(250,"Directory successfully changed.");
	}
	else
	{
		Respond(550,"Failed to change directory.");
	}

	return 1;
}
*/

int do_cwd(char *param)
{
	char buf[512]={0};
	int stat=0;
	char curpath[1024]={0};
	Intercept_Parameter(buf,param);//分离出参数
	if(IsAnonymous==1)//即匿名用户登入
	{
		//strcpy(curpath,anonymous_dir);
//		printf("path的值是 %s,目录的地址是...................................... %s\n",path,buf);
		if(buf[0]=='/')
		{
			sprintf(buf,"%s%s",cur_anonymous_dir,buf);
		}


		stat=chdir(buf);
		if(stat==0)
		{
			//printf("执行更改目录命令*********************************************\n");
			getcwd(cur_anonymous_dir,sizeof(cur_anonymous_dir));

			strcpy(path,cur_anonymous_dir+strlen(anonymous_dir));
			
			
			Respond(250,"Directory successfully changed.%s",path);
		}
		else
		{
			Respond(550,"Failed to change directory.");
		}
	}
	else
	{
		//getcwd(curpath,1024);
		//printf("CWD命令中执行chdir前的当前路径是: %s\n",curpath);
		stat=chdir(buf);
		//printf("执行chdir函数后函数返回值为 .......................  %d\n",stat);
		//memset(curpath,0,sizeof(curpath));
		//getcwd(curpath,1024);
		//printf("CWD命令中执行chdir后的当前路径是: %s\n",curpath);

		//printf("-------------------------------------------------------------\n");
		if(stat==0)
		{
			//printf("执行更改目录命令*********************************************\n");
			getcwd(curpath,sizeof(curpath));
			strcpy(path,curpath);
			Respond(250,"Directory successfully changed.");
		}
		else
		{
			Respond(550,"Failed to change directory.");
		}
	}	
	return 1;
} 

int do_cdup(char *param)
{
	char tmpPath[PATH_MAX+1];
	int stat;
	if(IsAnonymous==1)//匿名用户的情况下
	{

		int path_len=strlen(anonymous_dir);
		//int i;

		strcpy(tmpPath,cur_anonymous_dir);
//		printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%s\n",tmpPath);
		if(strlen(tmpPath)>path_len)//这个判断看看是不是返回到达匿名用户的相对路径的根目下边
		{
			stat=chdir("../");

			if(stat==0)
			{
				//取得用户的当前路径
				getcwd(cur_anonymous_dir,sizeof(cur_anonymous_dir));

				//strcpy(cur_anonymous_dir,tmpPath);
				strcpy(path,cur_anonymous_dir+strlen(anonymous_dir));
			
			
				Respond(250,"Directory successfully changed.%s",path);
			}
			else
			{
				Respond(550,"Failed to change directory.%s",cur_anonymous_dir);
			}
		}
	}
	else
	{
		strcpy(tmpPath,path);
		int len=strlen(tmpPath);
		int i=0;
		for(i=len-1;i>=0;i--)
		{
			if(tmpPath[i]=='/')
			{
				tmpPath[i]='\0';
				break;
			}
		}

		if(strlen(tmpPath)==0)
		{
			strcpy(tmpPath,"/");
		}
		stat=chdir(tmpPath);

		if(stat==0)
		{
			strcpy(path,tmpPath);
			Respond(250,"Directory successfully changed.");
		}
		else
		{
			Respond(550,"Failed to change directory.");
		}
	}
	return 1;
}
int do_syst(char *param)
{
	Respond(215,"UNIX Type:L8");
	return 1;
}
int do_pwd(char *param)
{
	Respond(257,"\"%s\"",path);
	return 1;
}

int do_type(char *param)
{
	char temp[2]={0};
	Intercept_Parameter(temp,param);
	//printf("Type %s\n",temp);
	if(temp[0]=='A')
	{
		Respond(200,"Switching to ASCII mode.");
	}else if(temp[0]=='I')
	{
		Respond(200,"Switching to Binary mode.");
	}

	return 1;
}
int do_port(char *param)
{
	char temp[25]={0};
	char ip[15]={0};//存放点分十进制IP地址
	int port=0;
	int stat;

	Intercept_Parameter(temp,param);//取得客户端地址 例如:192,168,0,1,15,70
	separate_ip_port(temp,ip,&port);
//	printf("IP:%s Port:%d............................................\n",ip,port);
	//下边是进行主动连接
	
	IsPASV=0;//将这个值设成0是明说现在用主功模式
	struct sockaddr_in cliaddr,servaddr;
	memset(&cliaddr, 0, sizeof(cliaddr));//将客户端套接字地址清零
	memset(&servaddr, 0, sizeof(servaddr));//将服务端套接字地址清零
	init_socket_addr(&cliaddr,NULL,20);//服务端用20端口跟客户端进行数据传输
	init_socket_addr(&servaddr,ip,port);
	datatrans_socket=CreateSocket();//创建一个跟客户端进行数据传输的套接字

	//只有root用户才可以对端口号低于1024的端口进行绑定所以在绑定端口前要更改当前进程的有效用户ID跟有效用户组ID
	//获得当前的有效用户ID和有效用户组ID,以便 于在绑定后,进行还原
	gid_t egid = getegid();//有效用户组ID
	uid_t euid = geteuid();//有效用户ID
	//切换为root用户的权限
	//这里要先改有效用户组然后再改有效用户,如果先改有效用户,那就没有权限再更改有效用户组
//	printf("更改有效用户权限为root用户...........................\n");
	setegid(0); 
	seteuid(0);
	//绑定套接字地址
	stat=bind_socket(datatrans_socket,&cliaddr);
//	printf("datatrans_socket=%d\n",datatrans_socket);
	if(stat<0)
	{
		printf("绑定20端口错误\n");
	}
	//切换回原来用户的权限
	setegid(egid);
	seteuid(euid);

	stat=connect_socket(datatrans_socket,&servaddr);
	if(stat==0)
	{
		Respond(200,"PORT command successful. Consider using PASV.");
	}
	else
	{
		Respond(530,"Connect Error.");
	}
	return 1;
}
int do_list(char *param)
{
	Respond(150,"Here comes the directory listing.");

	if(IsPASV==0)//IsPASV==0代表是主动模式
	{
		char curpath[1024]={0};
		getcwd(curpath,1024);
//		printf("当前路径是: %s\n",curpath);

		FileList(datatrans_socket);
//		printf("datatrans_socket=%d\n",datatrans_socket);
		close(datatrans_socket);

	}
	else 
	{
		//下边做被动模式
		struct sockaddr_in cliaddr;
		//int socket;//这个套接字是用来在被动模式下进行数据传送用的
		pasv_datatrans_socket=accept_socket(pasv_listen_socket,&cliaddr); //在被动模式下 datatrans_socket套接字是监听套接字
		FileList(pasv_datatrans_socket);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -