#!/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)