正文
vsftpd 自动安装脚本
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'cpy' import os
import re
import sys
import logging '''
@desc : install vsftpd software and configure
@time : 2018-07-02
''' reload(sys)
sys.setdefaultencoding('utf-8') class Config(object):
"""VSFTPD BASE CONFIG"""
VFTP_CONF = '/etc/vsftpd/vsftpd.conf'
VIR_CONF = '/etc/vsftpd/vconf'
VUSER = '/etc/vsftpd/vusers'
PAMFILE = '/etc/pam.d/vsftpd'
LOGFILE = '/etc/vsftpd/logs'
SYSUSER = '/etc/passwd'
DENYUSER = '/etc/vsftpd/user_list' VCONF_CONTENT_TMP = '''anonymous_enable=NO
#设成YES,允许匿名用户登陆
allow_writeable_chroot=YES
#vsftpd 2.3.5之后增强了安全检查,不允许限定在主目录下的用户具有写权限,该命令声明可以具有写权限。
local_enable=YES
#允许/禁止本地用户登陆 注意:主要是为虚拟宿主用户,如果该项目设定为NO那么所有虚拟用户将无法访问。
write_enable=YES
#设定可以进行写操作。
local_umask=022
#设定上传后文件的权限掩码,文件644,文件夹755
dirmessage_enable=YES
#设定开启目录标语功能
xferlog_enable=YES
#设定开启日志记录功能。
connect_from_port_20=YES
#设定端口20进行数据连接
xferlog_std_format=YES
#设定日志使用标准的记录格式
listen=YES
#开启独立进程vsftpd,不使用超级进程xinetd。设定该Vsftpd服务工作在StandAlone模式下。
pam_service_name=vsftpd
#设定,启用pam认证,并指定认证文件名/etc/pam.d/vsftpd
userlist_enable=YES
#设定userlist_file中的用户将不得使用FTP
tcp_wrappers=YES
#设定支持TCP Wrappers
chroot_local_user=YES
#限制所有用户在主目录
#以下这些是关于Vsftpd虚拟用户支持的重要配置项目。默认Vsftpd.conf中不包含这些设定项目,需要自己手动添加配置
guest_enable=YES
#设定启用虚拟用户功能
guest_username=www
#指定虚拟用户的宿主用户
virtual_use_local_privs=YES
#设定虚拟用户的权限符合他们的宿主用户
user_config_dir=/etc/vsftpd/vconf
#设定虚拟用户个人Vsftp的配置文件存放路径''' PAM_CONTENT_TMP = '''auth sufficient /lib64/security/pam_userdb.so db=/etc/vsftpd/virtusers
account sufficient /lib64/security/pam_userdb.so db=/etc/vsftpd/virtusers''' VUSER_CONF_CONTENT_TMP = '''local_root=/data/www/virtual/
#指定虚拟用户的具体主路径
anonymous_enable=NO
#设定不允许匿名用户访问
write_enable=YES
#设定允许写操作
local_umask=022
#设定上传文件权限掩码
anon_upload_enable=NO
#设定不允许匿名用户上传
anon_mkdir_write_enable=NO
#设定不允许匿名用户建立目录
idle_session_timeout=600
#设定空闲连接超时时间
data_connection_timeout=120
#设定单次连续传输最大时间
max_clients=10
#设定并发客户端访问个数
max_per_ip=5
#设定单个客户端的最大线程数,这个配置主要来照顾Flashget、迅雷等多线程下载软件
local_max_rate=50000
#设定该用户的最大传输速率,单位b/s''' class InitLogging(object):
""" 初始化日志输出配置 """ def __init__(self):
self.LOG = Config.LOGFILE def logconfig(self):
if not os.path.exists(self.LOG):
BASE_VSFTP_PATH = os.path.split(self.LOG)[0]
os.makedirs(BASE_VSFTP_PATH)
f = open(self.LOG, 'w')
f.close()
logging.basicConfig(level=logging.INFO, filename=self.LOG, filemode='a',
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') class ProgressBar(object):
def __flush_screen(self, string=''):
sys.stdout.write(string)
sys.stdout.flush() def progress(self, tasklist=[], width=100):
# 开始执行
for taskindex, task in enumerate(tasklist):
# 获取每个任务占用的进度条个数
scale = int(width / len(tasklist))
# 获取每个任务占用任务总数的百分比
score = int(100 / len(tasklist)) if taskindex == 0:
executestring = '\r{0:>2}% [{1}]{2}'.format(0, ' ' * width, os.linesep)
self.__flush_screen(string=executestring)
else:
executestring = '\r{0:>2}% [{1}{2}]{3}'.format(taskindex * score, '=' * taskindex * scale,
' ' * (width - taskindex * scale), os.linesep)
self.__flush_screen(string=executestring)
eval(task)
# 执行结束
endstring = '\r{0:>2}% [{1}] 完成{2}'.format(100, '=' * width, os.linesep)
self.__flush_screen(string=endstring) class Install(object):
"""INSTALL VSFTPD AND CONFIGURE""" def __init__(self):
pass def __checkvsftp_version(self):
"""check vsftpd version add configuration"""
faildmsg = u'vsftpd 版本获取失败'
vsftp_version = os.popen('rpm -qa |grep vsftpd').read().split('-')[1].split('.')
if vsftp_version:
l = [int(i) for i in vsftp_version]
if l[0] > 2 or (l[0] == 2 and l[1] > 3) or (l[0] == 2 and l[1] == 3 and l[2] >= 5):
return True
else:
return False
else:
raise RuntimeError(faildmsg) def __checkuser(self, username):
""" Check whether the input mapping user exists in the system """
with open(Config.SYSUSER, 'r') as f:
list = [username for line in f.readlines() if username == line.split(':')[0]]
if list:
return True
else:
return False def __deny_users(self):
"""return /etc/vsftpd/user_list deny users"""
with open(Config.DENYUSER, 'r') as f:
denyusers = [line for line in f.readlines() if not re.match('^\s*#.+.*$', line)]
return denyusers def rollback(self, *args):
"""UNINSTALL VSFTPD AND CONFIGURE"""
if len(args) > 0:
if self.__checkuser(username=args[0]):
uninstall_command = 'yum -y remove vsftpd && userdel -r %s && rm -rf %s* && rm -rf /etc/vsftpd' % (
args[0], Config.PAMFILE)
else:
uninstall_command = 'yum -y remove vsftpd && rm -rf %s* && rm -rf /etc/vsftpd' % Config.PAMFILE
else:
uninstall_command = 'yum -y remove vsftpd && rm -rf %s* && rm -rf /etc/vsftpd' % Config.PAMFILE if os.system(uninstall_command) != 0:
msg = u'卸载vsftpd 发生错误,请手动清除,以免产生垃圾文件'
print msg
logging.info(msg)
raise Exception(msg) def input_vuserinfo(self, numbers):
"""Trapping the virtual user information input"""
vuser_dict = {}
v_user = raw_input(u'请输入第%d个虚拟用户名:' % numbers)
v_pass = raw_input(u'请输入第%d个虚拟用户密码:' % numbers)
vuser_dict['username'] = v_user
vuser_dict['password'] = v_pass
return vuser_dict def install_vsftpd(self, username):
install_vsftpd_command = 'yum -y install pam pam-devel db4 db4-tcl vsftpd >>%s' % Config.LOGFILE
actionmsg = u'开始安装vsftp服务...'
errormsg = u'vsftpd 或其他依赖项安装失败。' logging.info(actionmsg)
if os.system(install_vsftpd_command) != 0:
logging.error(errormsg)
self.rollback(username)
raise Exception(errormsg) def deploy(self, username, parentpath):
"""configure the vsftpd"""
sucessfulmsg = u'配置成功。'
msg = u'配置错误,请检查是否已经存在或不允许的参数'
denyusers = self.__deny_users()
if username in denyusers:
logging.error(msg)
self.rollback(username)
raise Exception(msg)
if not self.__checkuser(username=username):
os.makedirs(parentpath)
os.rmdir(parentpath)
create_user_command = 'useradd %s -d %s -s /sbin/nologin >> %s' % (username, parentpath, Config.LOGFILE)
if os.system(create_user_command) != 0:
logging.error(msg)
self.rollback(username)
raise Exception(msg)
else:
logging.warning(msg)
self.rollback(username)
raise Exception(msg) back_conf_command = 'cp %s %s.bak >> %s' % (Config.VFTP_CONF, Config.VFTP_CONF, Config.LOGFILE)
if os.system(back_conf_command) != 0:
logging.error(msg)
self.rollback(username)
raise Exception(msg)
else:
logging.info(sucessfulmsg) f = open(Config.VFTP_CONF, 'w')
f.close() list_vconf_content = Config.VCONF_CONTENT_TMP.split(os.linesep) for line in list_vconf_content:
if re.match('^guest_username\=.+$', line.strip()):
line = 'guest_username=%s' % username
if re.match('^user_config_dir\=.+$', line.strip()):
line = 'user_config_dir=%s' % Config.VIR_CONF
if not self.__checkvsftp_version():
if re.match('^allow_writeable_chroot=YES$', line.strip()):
line = '#%s' % line.strip() with open(Config.VFTP_CONF, 'a') as f:
f.write(line.strip() + os.linesep)
logging.info(sucessfulmsg) def deploy_vritual_user(self, username, vuser):
"""config vritual users"""
sucessfulmsg = u'创建虚拟用户配置目录成功'
faildmsg = u'创建虚拟用户配置目录失败'
dbsucessfulmsg = u'生成虚拟用户数据文件成功'
dbfaildmsg = u'生成虚拟用户数据文件失败' if not os.path.exists(Config.VIR_CONF):
try:
os.makedirs(Config.VIR_CONF)
logging.info(sucessfulmsg)
except Exception:
self.rollback(username)
raise Exception(faildmsg)
f = open(Config.VUSER, 'w')
f.close() for v_user in vuser:
with open(Config.VUSER, 'a') as f:
f.write(v_user.get('username') + os.linesep)
f.write(v_user.get('password') + os.linesep) create_db_command = 'db_load -T -t hash -f %s %s.db' % (Config.VUSER, Config.VUSER) if os.path.exists("%s.db" % Config.VUSER):
os.remove('%s.db' % Config.VUSER) if os.system(create_db_command) != 0:
logging.error(dbfaildmsg)
self.rollback(username)
raise Exception(dbfaildmsg)
else:
logging.info(dbsucessfulmsg) def deploy_pam(self):
"""config virtual user by pam"""
baksucessfulmsg = u'备份成功'
bakfaildmssg = u'备份失败'
msg = u'开始配置pam认证...'
endmsg = u'配置pam认证完成'
logging.info(msg)
back_pam_command = 'cp %s %s.back' % (Config.PAMFILE, Config.PAMFILE) if os.path.exists('%s.back' % Config.PAMFILE):
os.remove('%s.back' % Config.PAMFILE) if os.system(back_pam_command) != 0:
logging.warning(bakfaildmssg)
else:
logging.info(baksucessfulmsg) f = open(Config.PAMFILE, 'w')
f.close() list_pam_content = Config.PAM_CONTENT_TMP.split(os.linesep) for line in list_pam_content:
p = re.compile(r'(?P<auth>.+\s+.+\s+.+\s+db=)(?P<vuserfile>.+)')
for dt in p.finditer(line):
line = dt.groupdict().get('auth') + Config.VUSER with open(Config.PAMFILE, 'a') as f:
f.write(line.strip() + os.linesep)
logging.info(endmsg) def deploy_virtual_config(self, username, parentpath, vuser):
"""config virtual user Configure"""
sucessfulmsg = u'创建虚拟用户目录或配置成功'
faildmsg = u'创建虚拟用户目录或配置错误'
existsmsg = u'已存在,正在尝试删除...' list_vuser_config_content = Config.VUSER_CONF_CONTENT_TMP.split(os.linesep)
for v_user in vuser:
vuser_path = os.path.join(parentpath, v_user.get('username'))
if os.path.exists(vuser_path):
logging.warning(existsmsg)
os.rmdir(vuser_path) try:
os.makedirs(vuser_path)
uid = int(os.popen('id %s -u' % username).read().strip())
gid = int(os.popen('id %s -g' % username).read().strip())
os.chown(vuser_path, uid, gid)
if not os.path.exists(vuser_path):
logging.error(faildmsg)
raise Exception(faildmsg)
logging.info(sucessfulmsg)
except Exception:
logging.error(faildmsg)
self.rollback(username)
raise Exception(faildmsg) vuser_config = os.path.join(Config.VIR_CONF, v_user.get('username'))
if os.path.exists(vuser_path):
f = open(vuser_config, 'w')
f.close()
else:
os.makedirs(Config.VIR_CONF)
f = open(vuser_config, 'w')
f.close() for line in list_vuser_config_content:
if re.match('^local_root=.+$', line.strip()):
line = 'local_root=%s' % vuser_path
with open(vuser_config, 'a') as f:
f.write(line.strip() + os.linesep)
logging.info(sucessfulmsg) def start_server(self, parentpath):
start_vsftpd_command = 'service vsftpd start'
if os.system(start_vsftpd_command) != 0:
logging.error(u'启动vsftpd服务失败')
raise Exception(u'启动vsftpd服务失败')
else:
logging.info(u'启动vsftpd服务成功') print ''
print u"安装vsftpd 完成!"
print ''
print ''
print u'-----' * 15
print u'1. 请在%s文件中查看登录的用户名和密码,一行用户名,一行密码' % Config.VUSER
print u'2. ftp数据存放在%s中' % parentpath
print u'3. 若FTP无法登陆,请检查主机防火墙是否关闭'
print u'-----' * 15 if __name__ == '__main__':
'''初始化日志输出'''
LOG = InitLogging()
LOG.logconfig() '''安装vsftpd服务'''
IS = Install()
username = raw_input(u'请输入vsftp的映射宿主用户名(本机账号):')
parentpath = raw_input(u'请输入用于存放ftp数据的目录:')
usercount = raw_input(u'您需要添加几个虚拟用户:')
vuserlist = []
if usercount.isdigit():
num = 0
for i in range(int(usercount)):
num += 1
vd = IS.input_vuserinfo(numbers=num)
vuserlist.append(vd)
else:
raise RuntimeError(u'您输入的参数不是整型') # IS.install_vsftpd(username=username)
# IS.deploy(username=username, parentpath=parentpath)
# IS.deploy_vritual_user(username=username, vuser=vuserlist)
# IS.deploy_pam()
# IS.deploy_virtual_config(username=username, parentpath=parentpath, vuser=vuserlist)
# IS.start_server(parentpath=parentpath) PB = ProgressBar()
tasks = ['IS.install_vsftpd(username=username)', 'IS.deploy(username=username, parentpath=parentpath)',
'IS.deploy_vritual_user(username=username, vuser=vuserlist)', 'IS.deploy_pam()',
'IS.deploy_virtual_config(username=username, parentpath=parentpath, vuser=vuserlist)',
'IS.start_server(parentpath=parentpath)']
PB.progress(tasklist=tasks, width=50)