一、FTP服务器
FTP,File Transfer Protocol 文件传输协议,FTP协议是一种古老的协议,它出现的比HTTP协议还要早,FTP主要应用于网络空间数据交换操作。ftp在工作时会有两个连接:一是命令连接,这个连接始终存在,只有使用bye命令退出会话时,连接才会断开;二是数据连接,数据传输完成,连接即断开。ftp有两种工作模式,主动模式和被动模式,主动模式工作在tcp/20端口,而被动模式则工作在tcp协议下的随机端口。通常FTP在身份认证时工作在21号端口。
在红帽系统下,vsftp是一款相对安全的FTP软件,在生产环境下可以使用它快速的实现FTP服务器的搭建。vsftp的用户认证支持两类用户,一是系统用户,二是虚拟用户。系统用户故名思义,就是使用系统上的普通用户作为FTP用户,这种方式操作相对简单。而虚拟用户则是使用一个系统用户映射成所有虚拟用户,访问时的文件目录是为此系统用户家目录。虚拟用户的用户帐号信息的存储分两种方式,一是将用户信息保存于一个hash编码的文件,奇数行为用户名,偶数行为密码;二是,存储于关系型数据库。我们知道,系统上几乎所有的和帐号认证有关的操作都是通过系统的pam模块负责管理,vsftp也不例外,我们使用mysql管理vsftp的帐号密码信息,则可以使用pam的mysql模块。pam默认不支持mysql数据库,因此在使用前需要安装此模块。
二、FTP服务器实现
1、安装软件
# yum -y install vsftpd mysql-server mysql-devel pam_mysql
2、创建数据库
mysql> create database vsftpd; mysql> grant all on vsftpd.* to 'vsftpuser'@'localhost' identified by 'vsftppass'; mysql> grant all on vsftpd.* to 'vsftpuser'@'127.0.0.1' identified by 'vsftppass'; mysql> grant all on vsftpd.* to 'vsftpuser'@'172.16.36.1' identified by 'vsftppass'; mysql> flush privileges; mysql> use vsftpd; mysql> create table users ( -> id int AUTO_INCREMENT NOT NULL, -> name char(20) binary NOT NULL, -> password char(48) binary NOT NULL, -> primary key(id) -> );
2、创建vsftp虚拟用户
insert into users(name,password) values('wu',md5('wu')); insert into users(name,password) values('json',md5('json'));
3、建立pam认证所需文件
#vi /etc/pam.d/vsftpd.mysql
添加如下两行:
auth required /lib64/security/pam_mysql.so user=vsftpuser passwd=vsftppass host=172.16.36.1 db=vsftpd table=users usercolumn=name passwdcolumn=password crypt=3 account required /lib64/security/pam_mysql.so user=vsftpuser passwd=vsftppass host=172.16.36.1 db=vsftpd table=users usercolumn=name passwdcolumn=password crypt=3
user: 数据库用户名
passwd: 数据库用户密码
host: 为数据库主机IP地址,如果是编译安装的数据库,只能填写远程IP地址,并给把这个IP地址授权给用户
db: 数据库名
table: 表名
usercolumn: 用户字段名
passwdcolumn: 用户密码字段名
crypt: 密码保存方式,0为明文,1为encrypt函数加密,2为password函数加密,3为MD5加密
注意:由于mysql的安装方式不同,pam_mysql.so基于unix sock连接mysql服务器时可能会出问题,此时,建议授权一个可远程连接的mysql并访问vsftpd数据库的用户。
4、建立虚拟用户映射的系统用户及对应的目录
# useradd -s /sbin/nologin -d /var/ftproot vuser # chmod go+rx /var/ftproot
5、请确保/etc/vsftpd/vsftpd.conf中已经启用了以下选项
anonymous_enable=NO #禁止匿名用户登录 local_enable=YES #允许本地用户登录 write_enable=YES #本地用户有写权限 anon_upload_enable=NO #匿名用户没有上传权限 anon_mkdir_write_enable=NO #匿名用户没有创建权限 chroot_local_user=YES #禁锢用户家目录
而后添加以下选项
guest_enable=YES guest_username=vuser
并确保pam_service_name选项的值如下所示
pam_service_name=vsftpd.mysql
6、重新启动服务,测试一下。
service vsftpd restart
打开CMD程序远程测试一下:
两个帐号都能成功登录!
二、通过web管理VSFTP
使用mysql管理vsftp用户的一个好处是,当服务器数据迁移时,只要把相关的数据库打包备份导入新的数据库就行了,管理相当方便。如果本机上有web服务器的话,我们还可以使用PHP开发一个web界面专门用来管理vsftp。
例如:我们新建一个虚拟主机:
<VirtualHost *:80> DocumentRoot "/var/www/html/vsftpadmin" ServerName ftpadmin.wubinary.com ServerAlias ftpadmin.wubinary.com ErrorLog "logs/ftpadmin.wubinary.com.error_log" CustomLog "logs/ftpadmin.wubinary.com.access_log" common ProxyRequests Off ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/html/vsftpadmin/$1 <Directory "/var/www/html/vsftpadmin"> Options None AllowOverride AuthConfig AuthType Basic AuthName "Vsftp Admin" AuthUserFile /etc/httpd/extra/.htpasswd Require valid-user </Directory> </VirtualHost>
对这个域名作身份认证,或者使用其它的方式对用户进行限制,用PHP写一个管理页面放在相关的目录下,我们就可以在web界面下管理我们的FTP服务器帐号了。
整个FTP服务器的搭建工作到此就完成了。vsftp web管理界面的PHP源码如下:
vsftpadmin.php
<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(E_ALL & ~ E_NOTICE);
//提示窗
function alertExit($msg,$flush=0){
// echo "<script language='javascript'>alert($msg);</script>";
echo "<script type='text/javascript' language='javascript'>alert('$msg');</script>";
if ($flush == 1) {
echo "<script type='text/javascript' language='javascript'>window.location.href='vsftpadmin.php'</script>";
}elseif ($flush == 2) {
echo "<script type='text/javascript' language='javascript'>history.back();self.location.reload();</script>";
}
}
//输出头部
function htmlheader($title){
echo <<<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{$title}</title>
<meta name="description" content="vsftp管理工具">
<meta name="keywords" content="linux,ftp,vsftp,mysql,pam_mysql,php">
<style type="text/css">
*{margin:0; padding:0; font-size:12px;}
ul,li{ list-style:none;}
a {text-decoration:none;color:#37a}
a:hover { background:#37a;color:white;padding:2px;}
img { border:0;}
.clear{ clear:both;}
.right{ float:right;}
.left{ float:left;}
#content{width:560px;margin:0 auto;text-align:center;margin-top:40px;}
.admin{border:1px solid #ccc; padding:30px;text-align:left;}
.admin h4{margin:10px 0;}
.admin p{margin:10px 0;}
.admin p .btn{padding:2px 4px;}
</style>
</head>
<body>
<div id="content">
<div class="admin">
<h4>{$title}</h4>
<p class="admin_btn">管理菜单:<a href="?ac=ftp">ftp状态</a> <a href="vsftpadmin.php">用户列表</a> <a href="?ac=add">添加用户</a></p>
EOF;
}
//输出尾部
function htmlfooter(){
echo <<<EOF
</div>
</div>
</body>
</html>
EOF;
}
//查询
function query($sql){
$result = mysql_query($sql) or die ("SQL语句查询错误: " . mysql_error());
if (mysql_num_rows($result) == 0) {
die('SQL: '.$sql.'<br>未查询到相关数据');
}
$arrReturn = array();
$index = 0;
while($arr = mysql_fetch_assoc($result)){
$arrReturn[$index] = $arr;
$index++;
}
return $arrReturn;
}
//添加
function adduser($name,$password){
if (strlen($name)<3) {
alertExit('用户名至少三位!',1);
}
if (strlen($password)<6) {
alertExit('密码必须大于八位!',1);
}
$sql = "select * from users where name='$name'";
$result = mysql_query($sql) or die ("SQL语句查询错误: " . mysql_error());
if (mysql_num_rows($result) > 0) {
alertExit('用户已存在',1);
}else{
$sql = "insert into users(name,password) values('$name',md5('$password'))";
$result = mysql_query($sql) or die ("添加角户出错: " . mysql_error());
// echo mysql_affected_rows();
if(mysql_affected_rows()==1){
alertExit("添加用户成功!",2);
}
}
}
//删除
function deluser($id){
$sql = 'select * from users where id='.$id;
$result = mysql_query($sql) or die ("SQL语句查询错误: " . mysql_error());
if (mysql_num_rows($result) == 0) {
alertExit('用户不存在',1);
}else{
$sql = 'delete from users where id='.$id;
$result = mysql_query($sql) or die ("删除角户出错: " . mysql_error());
if(mysql_affected_rows()==1){
alertExit("删除用户成功!",1);
}
}
}
//修改
function moduser($id,$name,$password){
$sql = "select * from users where id=$id";
$result = mysql_query($sql) or die ("SQL语句查询错误: " . mysql_error());
if (mysql_num_rows($result) == 0) {
alertExit('用户不存在',1);
}else{
$sql = "select * from users where name='$name' and id!=$id";
$result = mysql_query($sql) or die ("SQL语句查询错误: " . mysql_error());
if (mysql_num_rows($result) > 0) {
alertExit('用户已存在',1);
}else{
$sql = "update users set name='$name', password='$password' where id=$id";
$result = mysql_query($sql) or die ("修改角户出错: " . mysql_error());
if(mysql_affected_rows()==1){
alertExit("修改用户成功!",1);
}
alertExit("未作任何操作!",1);
}
}
}
//ftp状态管理
function ftpadmin($service='status'){
$arrFtp = array();
$result = mysql_query("SELECT id FROM users");
$num_rows = mysql_num_rows($result);
$arrFtp['usercount'] = $num_rows;
if($service=='status'){
$arrFtp['status'] = `service vsftpd status`;
}elseif($service=='restart'){
$arrFtp['status'] = `service vsftpd restart`;
}elseif ($service=='stop') {
$arrFtp['status'] = `service vsftpd stop`;
}
if(empty($arrFtp['status'])){
$arrFtp['status'] = 'Unknow';
}
return $arrFtp;
}
$conn = @mysql_connect('127.0.0.1','root','') or die ('数据库连接错误: ' . mysql_error());
mysql_select_db('vsftp', $conn) or die ('选择数据库错误: ' . mysql_error());
$strAction = htmlspecialchars($_GET['ac']);
$arrAction = array('del', 'mod', 'add', 'ftp');
if (! in_array($strAction, $arrAction)) {
htmlheader('Vsftp 管理');
$arrUserList = query('select * from users');
foreach ($arrUserList as $key => $value) {
?>
<form action='./vsftpadmin.php?ac=mod' method='post'>
<p><label>name:</label> <input type="text" name="name" value="<?php echo $value['name'];?>">
<label>password:</label> <input type="password" name="password" value="<?php echo $value["password"];?>">
<input type='hidden' name='id' value="<?php echo $value["id"];?>">
<input type="submit" value="修改" class="btn"> <input type="button" οnclick="window.location.href='?id=<?php echo $value["id"];?>&ac=del'" value="删除" class="btn"></p>
</form>
<?php }
htmlfooter();
}else{
if ($strAction=='add') {
if ($_SERVER['REQUEST_METHOD']=='POST') {
$name = htmlspecialchars($_POST['name']);
$password = htmlspecialchars($_POST['password']);
adduser($name,$password);
}else{
htmlheader('添加用户');
?>
<form action='./vsftpadmin.php?ac=add' method='post'>
<p><label>name:</label> <input type="text" name="name" value="">
<label>password:</label> <input type="password" name="password" value="">
<input type="submit" value="提交" class="btn"> <input type="reset" value="重置" class="btn"></p>
</form>
<?php
htmlfooter();
}
}elseif ($strAction=='del') {
$intId = intval($_GET['id']);
if($intId!=''){
deluser($intId);
}else{
alertExit('参数错误!',1);
}
}elseif ($strAction=='mod') {
$intId = intval($_POST['id']);
$name = htmlspecialchars($_POST['name']);
$password = htmlspecialchars($_POST['password']);
if($name!='' && $password!=''){
moduser($intId,$name,$password);
}else{
alertExit('参数错误!',1);
}
}elseif($strAction=='ftp'){
htmlheader('FTP状态');
$arrFtp = array();
$status = htmlspecialchars($_GET['status']);
if($status=='restart')$arrFtp = ftpadmin('restart');
elseif($status=='stop')$arrFtp = ftpadmin('stop');
else $arrFtp = ftpadmin();
?>
<p><label>用户总数:</label> <?php echo $arrFtp['usercount'];?> <br>
<label>vsftp状态:</label> <?php echo $arrFtp['status'];?>
<input type="button" οnclick="window.location.href='?ac=ftp&status=restart'" value="重启" class="btn"> <input type="button" οnclick="window.location.href='?ac&status=stop'" value="停止" class="btn"></p>
<?php
htmlfooter();
}else{
die('无效的地址!');
}
}
转载于:https://blog.51cto.com/wubinary/1386620