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)
相關文章
相關標籤/搜索