池偏一 | 博客 DEDICATED OPERATION AND MAINTENANCE DEVELOPMENT.
登录
X
X
  • vsftpd 虚拟用户限定在虚拟用户目录

  • 1.安装vsftpd及所需依赖工具


    yum -y install pam pam-devel db4 db4-tcl vsftpd


    2.更名默认配置文件,以便恢复


    cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak #主配置文件
    cp /etc/pam.d/vsftpd /etc/pam.d/vsftpd.bak #认证配置文件


    3.创建虚拟ftp账户和数据库文件


    vim /etc/vsftpd/vusers  #添加帐号和密码
    vuserone                              #一行帐户
    passwdone                           #一行密码
    vusertwo
    passwdtwo

    4. 根据虚拟ftp账号密码文件创建数据文件(该文件是真正使用的)

    db_load -T -t hash -f /etc/vsftpd/vusers /etc/vsftpd/vusers.db


    5.创建ftp根目录及虚拟用户映射的系统账户


    mkdir -p /data
    useradd -d /data/ftp -s /sbin/nologin ftpuser #添加系统用户ftpuser


    6.创建虚拟用户认证文件


    >/etc/pam.d/vsftpd #清空认证文件
    vi /etc/pam.d/vsftpd       #添加以下内容,指定pam认证的db文件
    #%PAM-1.0
    auth    sufficient      /lib64/security/pam_userdb.so    db=/etc/vsftpd/vusers
    account sufficient      /lib64/security/pam_userdb.so    db=/etc/vsftpd/vusers


    7.最后配置主配置文件


    >/etc/vsftpd/vsftpd.conf #清空原配置文件
    vim /etc/vsftpd/vsftpd.conf #修改成如下内容
    anonymous_enable=NO
    #设成YES,允许匿名用户登陆
    allow_writeable_chroot=YES
    #2.3.5以下版本不需要配置,否则无法启动,提示配置文件错误
    #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的配置文件存放路径

    7. 配置虚拟用户配置文件


    mkdir -p /etc/vsftpd/vconf #添加虚拟用户配置目录
    mkdir -p /data/ftp/vuserone #虚拟用户1对应存放数据目录
    mkdir -p /data/ftp/vusertwo #虚拟用户2对应存放数据目录
    chown -R ftpuser.ftpuser /data/ftp
    vim /etc/vsftpd/vconf/vuserone #编辑虚拟用户1的配置文件,添加如下内容
    local_root=/data/ftp/vuserone
    #指定虚拟用户的具体主路径
    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
    vim /etc/vsftpd/vconf/vusertwo #编辑虚拟用户2的配置文件,添加如下内容
    local_root=/data/ftp/vusertwo
    #指定虚拟用户的具体主路径
    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

    8.重启vsftpd 服务: 

    service vsftpd restart


  • posted @ 2019-01-29 by 池偏一 阅读(42) 评论(0)
  • 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)


    使用图示:

    image.png

  • posted @ 2019-01-29 by 池偏一 阅读(68) 评论(0)
© 2017 池偏一 | 赣ICP备 17014207号