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

📄 ftpcmd.c

📁 linux下的FTP服务器。支持现在主流的FTP客户端软件。增加了一些额外的功能。
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdlib.h>
#include "Public.h"
#include "Ftpcmd.h"


// ftp 全局变量结构体
//extern FtpGlobalVar ftp_global_var;

/************************************
	用户登入处理函数
**************************************/
int do_user(char * param)
{
	
	// 没有办法测试
	if (ftp_global_var.IsLogin)
	{
		ServiceEcho(503,"Already logged in.");
		return -1; // 已经登入 不做处理
	}
	
	//int isanonymous =0;
	if (ftp_config.anonymous_enable==1 && strcmp("anonymous",param)==0)
	{
		
		ftp_global_var.isanonymous =1;
	}

	
	// 参数判断
	if (0== strlen(param))
	{
		ServiceEcho(500,"USER conmond request a param.");
		return -1;
	}
	

	ServiceEcho(311,"Please specify the password.");
//	ServiceEcho(311,temp);
	
	
	strcpy(ftp_global_var.username,param);	
	return 0;
}

/****************************************
	用户和密码同时进行验证的 最重要的是对匿名登入的一个处理
****************************************/
int do_pass(char * param)
{
	//if (ftp_global_var.isanonymous) // 为匿名用户登入时
	if(strcmp(ftp_global_var.username,"anonymous")==0)
	{
		strcpy(ftp_global_var.username,"ftp"); // 用默认的FTP 登入系统
	}
	strcpy(ftp_global_var.pass,param);

	struct  passwd * pwd;
	struct  spwd * showpwd;


	/*
	char temp11[80]={0};
	sprintf(temp11,"username=%s",ftp_global_var.username);
	ServiceEcho(200,temp11);

*/
	pwd=getpwnam(ftp_global_var.username);
	showpwd=getspnam(ftp_global_var.username);

	if (pwd ==NULL || showpwd==NULL)
	{
		ServiceEcho(530,"Login Error.");
		return -1; // 登入失败
	}
	
	char temp[13];
	strncpy(temp,showpwd->sp_pwdp,12);
	//temp[13]='\0';

	if (!ftp_global_var.isanonymous) // 
	{
		// 不是匿名用户登入时,需要验证
		if (strcmp( ((char *) (crypt(param,temp) ) ),showpwd->sp_pwdp )!=0)
		{
			// 登入失败
			ServiceEcho(530,"Login Error.");
		}
	}

		// 成功登入的情况
		strcpy(ftp_global_var.currpath,pwd->pw_dir); // 当前目录
		strcpy(ftp_global_var.pass,param); // 保存密码
		ftp_global_var.IsLogin = 1; // 登入状态
		setegid(pwd->pw_gid); // 用户ID 
		seteuid(pwd->pw_uid); // 组ID
		ftp_global_var.uid = pwd->pw_uid;
		ftp_global_var.gid = pwd->pw_gid;

		chdir(pwd->pw_dir); // 改变当前工作目录
		

		ServiceEcho(230,pwd->pw_dir);

		return 0;
}




int set_path(char * param)
{
	//getcwd(ftp_global_var.currpath,PATH_MAX); // 当前工作目录
	/*
	if (strcmp(param,"."))
	{
	}else if (strcmp(param,".."))
	{
		
	}else
	*/
	
	if (strcmp(ftp_global_var.username,"ftp")==0)
	{
		//ftp匿名变量的时候
		if (strstr(param,"/")!=0)
		{ // 绝对路径
				char tempdir[PATH_MAX]={0};
				strcat(tempdir,"/var/ftp/");
				strcat(tempdir,param);
				strcpy(ftp_global_var.currpath,tempdir);
		}
		else //if(strcmp(param,""))
		{
			// 相对路
			getcwd(ftp_global_var.currpath,PATH_MAX);
			strcat(ftp_global_var.currpath,"/");
			strcat(ftp_global_var.currpath,param);
		}
		return 0;
	}


	if (strstr(param,"/")!=NULL)
	{
		//found 绝对路径
		strcpy(ftp_global_var.currpath,param);
	}
	else
	{
		//not found
		strcat(ftp_global_var.currpath,"/");
		strcat(ftp_global_var.currpath,param);
	}
}
/********************
	改变工作目录
*************************/
int do_cwd(char * param)
{
	// 路径变更
	
	// ?????? 关于路径的判断
	/*
	getcwd(ftp_global_var.currpath,PATH_MAX); // 更新
	strcat(ftp_global_var.currpath,"/");
	strcat(ftp_global_var.currpath,param);
	*/

	set_path(param);
	if (chdir(ftp_global_var.currpath)<0)
	{
		ServiceEcho(550,"Failed to change directory.");
		//ServiceEcho(550,ftp_global_var.currpath);
		getcwd(ftp_global_var.currpath,PATH_MAX); // 更新
		return -1;
	}
	getcwd(ftp_global_var.currpath,PATH_MAX); // 更新
	ServiceEcho(250,"Directory successfully changed");

	//ServiceEcho(250,ftp_global_var.currpath);
	return 0;
}

/*回到上一层目录*/
int do_cdup(char * param)
{

	if (strcmp(ftp_global_var.username,"ftp") == 0 && strcmp(ftp_global_var.currpath,"/var/ftp")==0)
	{
		do_cwd(".");
	}
	else
	{
		do_cwd("..");
	}
	
	return 0;
}

int do_syst(char * param)
{
	ServiceEcho(215,"UNIX Type: L8");
	return 0;
}


// 打印当前目录
int do_pwd(char * param)
{	
	char temp[PATH_MAX]={0};
	char * p=NULL;


	if ( strcmp(ftp_global_var.username,"ftp") == 0 )
	{
		if(p=strstr(ftp_global_var.currpath,"/var/ftp"))
		{
			if (strlen(ftp_global_var.currpath)==8)
			{
				sprintf(temp,"\"%s\"","/");
			}else
			{
				sprintf(temp,"\"%s\"",&ftp_global_var.currpath[8]);
			}
			ServiceEcho(257, temp);	
		}
		else
		{
			// 相对路径
		}
	}
	else
	{
		sprintf(temp,"\"%s\"",ftp_global_var.currpath);
		ServiceEcho(257, temp);
	}
	return 0;
}

int do_type(char * param)
{
	if (strcmp(param,"A")==0)
	{
		ftp_global_var.transmode='A';
		ServiceEcho(200,"Switching to ASCII mode.");
	}else if(strcmp(param,"I")==0)
	{
		ftp_global_var.transmode='I';
		ServiceEcho(200,"Switching to BINARY mode.");
	}
	return 0;
}

/*
	数据端口,主要向服务器发送客户数据连接的端口,
	格式为PORT h1,h2,h3,h4,p1,p2,其中32位的IP地址用h1,h2,h3,h4表示,
	16位的TCP端口号用 p1,p2表示。
*/

// TO DO  超过时间 应该自动却换为 psav 进行处理 
// ?????????????????
// ??????????????????????????????????????

int do_port(char * param)
{
	int ip[4]={0}; // ip四个段
	int port[2]={0}; // port 两个段
	char str_ip[16]={0};
	int resport=-1;
	// 提取IP
	sscanf(param,"%d,%d,%d,%d,%d,%d",&ip[0],&ip[1],&ip[2],&ip[3],&port[0],&port[1]);
	sprintf(str_ip,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
	
	// 计算port
	resport=port[0]*256+port[1];
	char temp[10]={0};
	//	sprintf(temp,"%d",resport);

	//保存到相应的全局变量
	strcpy(ftp_global_var.datacon_ip,str_ip);	
	ftp_global_var.datacon_port = resport;
	ServiceEcho(200,"PORT command successful. Consider using PSAV");
	ftp_global_var.IsPort =1; // 保存主动模式
	ftp_global_var.port_port = resport;
	strcpy(ftp_global_var.port_ip,str_ip);
	return 0;
}


/*************************
  主动连接
*************************/
int Port_connect()
{
		struct sockaddr_in servaddr,cliaddr;
		int servfd;
		int clifd;
		memset(&servaddr,0,sizeof(servaddr));
		memset(&cliaddr,0,sizeof(cliaddr));
		
		servaddr.sin_family = AF_INET;
		servaddr.sin_port = htons(20);
		//servaddr.sin_addr.s_addr = inet_addr();
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

		cliaddr.sin_family =AF_INET;
		cliaddr.sin_port = htons(ftp_global_var.port_port);
		cliaddr.sin_addr.s_addr = inet_addr(ftp_global_var.port_ip);
		
		int len=sizeof(cliaddr);
		ftp_global_var.uid = geteuid();
		ftp_global_var.gid = getegid();

		seteuid(0);
		setegid(0);
		// 只有ROOT 用户才有权限绑定20端口
		// ????????????? 调用语义是有问题的 借用一个函数
		servfd = Tcp_service(ftp_global_var.port_ip,20);
		//servfd = socket(AF_INET,SOCK_DGRAM,0);
		

		seteuid(ftp_global_var.uid);
		setegid(ftp_global_var.gid);
	
		connect(servfd,(struct sockaddr *)&cliaddr,len);

		ServiceEcho(150,"Here comes the directory listing");
}

/*****************************
	被动连接
****************************/
int Pasv_connect()
{
	int clisockfd;
	clisockfd = Tcp_accept(ftp_global_var.pasv_mode_sockfd,NULL,NULL);
	ServiceEcho(150,"Here comes the directory listing"); // 说明已经连接上了。
	Tcp_close(ftp_global_var.pasv_mode_sockfd); // 关闭监听
	return clisockfd;
}

/********************************
	列目录详细清单
*********************************/
int do_list(char * param)
{
	// 两种模式,调用不同的方式

	if (ftp_global_var.IsPasv == 0 && ftp_global_var.IsPort==0)
	{
		ServiceEcho(425,"Use PORT or PASV first.");
		return 0;
	}
	
	if (ftp_global_var.IsPasv)
	{
		// 被动模式
		//int clisockfd = Pasv_connect();
		
		int clisockfd = Tcp_accept(ftp_global_var.pasv_mode_sockfd,NULL,NULL);
		ServiceEcho(150,"Here comes the directory listing"); // 说明已经连接上了。
		Tcp_close(ftp_global_var.pasv_mode_sockfd); // 关闭监听
		
		
		// 发送目录

		send_list(clisockfd);

		Tcp_close(clisockfd);
		ftp_global_var.IsPasv = 0;
		ServiceEcho(226,"Directory send Ok");
	}else if (ftp_global_var.IsPort==1)
	{
		// 主动模式
		struct sockaddr_in servaddr,cliaddr;
		int servfd;
		int clifd;
		memset(&servaddr,0,sizeof(servaddr));
		memset(&cliaddr,0,sizeof(cliaddr));
		
		servaddr.sin_family = AF_INET;
		servaddr.sin_port = htons(20);
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

		cliaddr.sin_family =AF_INET;
		cliaddr.sin_port = htons(ftp_global_var.port_port);
		cliaddr.sin_addr.s_addr = inet_addr(ftp_global_var.port_ip);
		
		int len=sizeof(cliaddr);
		ftp_global_var.uid = geteuid();
		ftp_global_var.gid = getegid();

		seteuid(0);
		setegid(0);
		// 只有ROOT 用户才有权限绑定20端口
		// ????????????? 调用语义是有问题的 借用一个函数

		servfd = Tcp_service(ftp_global_var.port_ip,20);

		//servfd = socket(AF_INET,SOCK_DGRAM,0);
		seteuid(ftp_global_var.uid);
		setegid(ftp_global_var.gid);
	
		connect(servfd,(struct sockaddr *)&cliaddr,len);

		ServiceEcho(150,"Here comes the directory listing");

		send_list(servfd);

		shutdown(servfd,0);

		Tcp_close(servfd);
		//Tcp_close(clifd);
		 ftp_global_var.IsPort=0;
		ServiceEcho(226,"Directory send Ok");
		// 主动模式 服务器20 端口去。链接客户端
	}
	return 0;
}
// 列出段清单
int do_nlst(char * param)
{return 0;}
// 删除目录
int do_rmd(char * param)
{
	// ?????????????
	// ??????????????

	if (rmdir(param)==-1)
	{
		//perror("do_param remove error.");
		ServiceEcho(550,"Permission denied");
	}
	else
	{
		ServiceEcho(250,"Remove directory operation successful.");
	}
	return 0;
}

// 创建目录
int do_mkd(char * param)
{
	if (mkdir(param,0755)==-1)
	{
		perror("mkdir error.\n");
	}

	char temp[PATH_MAX]={0};
	getcwd(temp,PATH_MAX);
	strcat(temp,param);
	ServiceEcho(205,temp);
	return 0;
}

/* 删除文件*/
int do_dele(char * param)
{
	if (remove(param)==-1)
	{
		
	}
	ServiceEcho(205,"Delete file ok.");
	return 0;
} 

/********************************************
	重新初始化。此命令终止USER,重置所有参数,
	控制连接仍然打开,用户可以再次使用USER命令。
*********************************************/
int do_rein(char * param)
{
	ftp_global_var.IsLogin=0; // 设置为没有登入状态
	memset(ftp_global_var.username,0,sizeof(ftp_global_var.username));
	ftp_global_var.isanonymous=0;
	ServiceEcho(200,"Rein OK.");
	seteuid(0);
	setegid(0);
	return 0;
}
/***********************
	帮助命令
**************************/
int do_help(char * param)
{
	//ServiceEcho(502,"I don't have help.");

	ServiceEcho(214,"------sitehelp-----");
	ServiceEcho(214,"USER - 登入用户名   PASS - 登入密码  QUIT 退出");
	ServiceEcho(214,"CWD  - 改变工作目录 RMD - 删除目录   MKD - 新建目录");
	ServiceEcho(214,"PWD  - 打印当前目录 LIST- 列出详细清单" );
	ServiceEcho(214,"STAT - 控制状态     SIZE - 获取文件大小");
	ServiceEcho(214,"------help----------");
	return 0;
}

// 退出
int do_quit(char * param)
{
	ServiceEcho(221,"Goodbye!");
	// 退出USER 登入
	Tcp_close(ftp_global_var.CtrSockfd); // 关闭控制连接
	return 0;
}


/****************************************
	断点续传
*****************************************/
int do_rest(char * param)
{
	long endseek=atoi(param);
	char temp[80]={0};
	//puts(param);
	if (ftp_global_var.IsPasv == 0 && ftp_global_var.IsPort == 0)
	{
		sprintf(temp,"Restart position accepted (%d)",0);
	}else
	{
		sprintf(temp,"Restart position accepted (%d)",param);
	}
	
	ServiceEcho(350,temp);                 
	return 0;
}

/*********************************
	被动连接
	此命令要求服务器数据传输进程在随机端口上监听,进入被动接收请求的状态
**********************************/
int do_pasv(char * param)
{	
	//  被动方式 建立数据链接  发送IP 和随机端口给 客户端,
	// 然后客服端会来链接他 
	int datalistenfd=0;

	char localip[16]={0};
	getlocalip(localip);

	datalistenfd = Tcp_service(localip,0); // 0#port 就是随机port
	
	//提取端口
	struct sockaddr_in pasv_addr;
	int len=sizeof(pasv_addr);
	memset(&pasv_addr,0,sizeof(pasv_addr));
	

⌨️ 快捷键说明

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