vsftpd+pam_mysql+shell

#!/bin/bash
#describe:自动检测user表,如果有关于user表的操作,则更新配置文件
#vsftpd+pam_mysql+shell
#这里用bash 版本>4.0 因为使用到了定义关联数组
#author:wujp [email protected]
#支持:插入更新|修改一条或多条更新|暂不支持删除操作,删除操作已状态判断
#更新内容:路径|名称|权限|ip限制
#版本:1.0.1

#vsftpd
VSFTPDPATH='/usr/local/sbin/vsftpd'
FTPCONFPATH='/etc/vsftpd/userconf/'
FTPFILEPATH='/home/virtual/'

#mysql
MYSQLPATH='/app/mysql5/'
MYSQLDB=''
MYSQLUSER=''
MYSQLPASS=''

#监控的表分割符
TABLE='user'
declare -A FIELDS #定义关联数组
FIELDS=([user_k]=username [permiss_k]=permiss [status_k]=status [allow_ip_k]=allow_ip)
SEP='|'
RE_SEP=','

#配置文件模板
TEMPLTE="
local_root={root}\n
write_enable=YES\n
anon_upload_enable=YES\n
anon_world_readable_only=NO\n
anon_mkdir_write_enable=YES\n
anon_other_write_enable=YES\n
cmds_allowed={cmd}\n"

#用户目录权限
USER='virtual'
GROUP='users'
MODE='700'

#创建日志目录
LOGPATH='/data0/logs/'
if [ ! -d $LOGPATH ];then
   mkdir -pv $LOGPATH >/dev/null
fi
LOGFILE=$LOGPATH'pam_mysql.log'
CONF_TMP=$LOGPATH'tmpconf'

MONITOR_TIME=''

#允许传参数
if(($#>0));then
    case $1 in
      -v)
      echo "ftpm version:ftpm/1.0.1"
      exit
      ;;
      -h)
      echo -e "---------------------welcome----------------------------!\n
    First of all, the file is used for monitoring Table of VSFTPD
configuration file. This file can be monitored Table insert, update, but
does not support Table delete operation.
    Then, update the configuration contains The following contents:
the configuration file name, the user local path ,the user Permissions,
the user was allowed to IP.
    An IP can only corresponding to a user, but a user can correspond to
multiple IP
    At last. Welcome to provide more, thank you!

   -v version
   -h help
   -c Clear the cache file, such as:configuration temporary file
   How long does it take from the recent monitoring :
   -M  minutes
   -H  hours
   -d  day
   -w  week
   -m  month
   -y  years
"
      exit
      ;;
      -c) #清除临时文件
      if [ -f $CONF_TMP ];then
          rm -rf $CONF_TMP >/dev/null
      fi
      exit
      ;;
      *)
      declare -A time_type
      time_type=([-M]=minutes [-H]=hours [-d]=day [-w]=week [-m]=month [-y]=years)

      #判断是否存在于数组中
      echo ${!time_type[*]} |sed 's/-//g' |grep `echo $1|sed 's/-//'` >/dev/null
      if [ ! $? == 0 ];then
         echo "sorry,sir.can't found the argument,please '-h' operation"
         exit
      fi

      #判断是否是数字
      echo $2|grep -e'^[0-9]\+$' >/dev/null
      
      if(($?==0));then
          MONITOR_TIME='-'$2' '${time_type[$1]}
      else
         echo "sorry,sir.please specify the argument"
         exit
      fi
      ;;
    esac
fi
if [ -z "$MONITOR_TIME" ];then
  MONITOR_TIME='-1 minutes'
fi

if [ ! -f $CONF_TMP ];then
   echo -e $TEMPLTE >$CONF_TMP
fi

#日志方法,type:error|waring|  string:error string
write_log(){
   declare -A error_type
   error_type['e']='ERROR'
   error_type['w']='WARING'
   error_type['t']='TRUE'
   
   now=$(date "+%F %H:%M:%S")

   echo $2
   echo $now"   "${error_type[$1]}":"$2 >>$LOGFILE
}

#binlog临时文件
BINLOGTMP=$LOGPATH'binlog_tmpfile'

#间隔时间 采用inotify 监听文件
#INTVAL_TIME='30'


#权限过滤,过滤非法权限  cmds
#必须:PASS,QUIT,USER,REIN,PASV,TYPE,HELP
#不允许:ABOR PORT SITE ACCT STAT STOU STRU SYST NOOP MODE
#1.显示目录:LIST|CWD|PWD 同时选   MDTM,NLST SIZE,CDUP 
#2.重命名:RNTO|RNFR 同时选
#2.下载:RETR
#2.上传:STOR
#2.追加:APPE 
#2.删除文件:DELE
#3.删除目录:RMD
#3.新建目录:MKD


ALLOW_PERMISS='PASS,QUIT,USER,REIN,PASV,TYPE' #TYPE也必须默认
DENY_PERMISS=(ABOR PORT SITE ACCT HELP STAT STOU STRU SYST MODE)
permiss_filter(){
    local res=$1
    for per in ${DENY_PERMISS[*]}
    do
       res=$(echo $res |sed "s/$per,//g"|sed "s/,$per//g")
    done

    echo $res
}

#生成和修改配置文件 username cmds
write_conf(){
   file=$FTPCONFPATH$1

   if [ -f $file ];then
     rm -rf $file >/dev/null
      write_log 't' 'delete conf file '$1
   fi
   
   cmd_all=$(echo $2|sed "s/$SEP/$RE_SEP/g")
   cmd_all=$(echo $ALLOW_PERMISS$RE_SEP$cmd_all |sed "s/$RE_SEP$//")
   cmd_all=$(permiss_filter $cmd_all)
   
   path_file=$FTPFILEPATH$1
   sed "s#{root}#$path_file#" $CONF_TMP |sed "s/{cmd}/$cmd_all/" >$file 
   
   if(($?==0));then
      write_log 't' 'conf file '$1' is write true'
   else
      write_log 'e' 'conf file '$1' is write false!'
   fi
   
   if [ ! -f $path_file ];then
      mkdir -pv $path_file >/dev/null
      write_log 't' 'user local path '$file' is make true'
   fi
   
   chmod $MODE $path_file
   if(($?==0));then
      write_log 't' 'conf file '$1' is change mode true'
   else
      write_log 'e' 'conf file '$1' is change mode false!'
   fi

   chown -R $USER.$GROUP $path_file
   if(($?==0));then
       write_log 't' 'conf file '$1' is change user true'
   else
       write_log 'e' 'conf file '$1' is change user false!'
   fi
}

#ip写入方法
write_ip(){
    if [ ! -z $1 ];then
       sed "/$1/d" /etc/hosts.allow |sed "/$2/d"  >${LOGPATH}allow_tmp #删除ip和名称对应的行
       
       mv -f ${LOGPATH}allow_tmp /etc/hosts.allow >/dev/null

       write_log 't' 'conf file '$1' allow_ip is delete true'

       echo "vsftpd:"$2":setenv VSFTPD_LOAD_CONF "$FTPCONFPATH$1 >> /etc/hosts.allow 

       write_log 't' 'conf file '$1' allow_ip is change true'
    fi
}
   
   #每次只读五分中前的记录
   TIME=$(date -d "$MONITOR_TIME" "+%F^%H:%M:%S") #这里中间用^不然就没用,不能用空格
   
   #得到最近的binlog
   num=$(ls $MYSQLPATH'data'/|grep -v "mysql-bin.index" |grep "mysql-bin.*"|awk -F[.] '{print $2}'|sort -rn |head -1)
   
   if(($?==0));then
      BINLOG=$MYSQLPATH"data/mysql-bin."$num
      write_log 't' 'binlog is '$BINLOG
   else
      write_log 'e' 'binlog is not found!'
      continue
   fi
   
   #得到符合要求的binlog
   if [ ! -z $BINLOG ];then
        ${MYSQLPATH}bin/mysqlbinlog -d${MYSQLDB} -f -s --start-datetime=$TIME $BINLOG >$BINLOGTMP #这里的写法一定要注意,就这么简单,不要搞什么单引号,双引号
   fi
   
   #处理binlog
   if [ -f $BINLOGTMP ];then
      cat $BINLOGTMP |while read line   
      do 
         RESTART=1
         #得到插入数据  INSERT INTO user (username, passwd) VALUES (test, nala)
         line=$(echo $line|sed 's/\/\*.*\*\///g' |sed "s/[\/|\!|\*|;|\(|\)]//g")
         
         ins_line=$(echo $line |sed "s/[\'|\`]//g")
         echo $ins_line |grep "INSERT INTO "$TABLE >/dev/null  #INSERT IGNORE INTO 
         
         if(($?==0));then
             
             eval $(echo $ins_line |sed "s/^INSERT INTO $TABLE//" |sed 's/VALUES.*//'|sed 's/ //g'|awk -F[,] '{for(k=1;k<=NF;k++) print "field["k"]="$k}')
             eval $(echo $ins_line |sed 's/^.*VALUES//' |sed 's/ //g'|awk -F[,] '{for(k=1;k<=NF;k++) print "value["k"]="$k}')
             
             #获取名称和权限
             for key in ${!field[*]}
             do
                  #获取用户名
                  if [ ${field[$key]} == ${FIELDS['user_k']} ];then 
                      username=${value[$key]}
                  fi

                  #获取权限  权限判断,过滤非法权限
                  if [ ${field[$key]} == ${FIELDS['permiss_k']} ];then 
                      cmds=$(echo ${value[$key]})
                  fi

                  #获取status
                  if [ ${field[$key]} == ${FIELDS['status_k']} ] && [ ${value[$key]} != 'ONLINE' ];then
                     if [ -f $FTPCONFPATH$username ];then
                        rm -rf $FTPCONFPATH$username >/dev/null
                        write_log 't' 'delete not online conf file '$FTPCONFPATH$username' of insert'
                     fi

                     username=''
                  fi

                  #获取allow_ip  可以加上检查 /etc/hosts.deny 是否只包涵  vsftpd:ALL
                  if [ ${field[$key]} == ${FIELDS['allow_ip_k']} ];then
                      #echo 'write_ip'                     
                      write_ip $username ${value[$key]}
                  fi
             done
             
             #生成配置文件更改权限和用户组信息
             if [ ! -z $username ];then
                #echo 'write conf'
                write_conf $username $cmds
             fi
         fi
         
         #得到修改数据  UPDATE user SET passwd=nala WHERE id=1 直接取where条件
         echo $ins_line |grep "UPDATE "$TABLE" SET" >/dev/null
         if(($?==0));then
             let RESTART+=1
             ID=$(echo $line |sed 's/.*WHERE //')
             
             #考虑值有空的情况
             str=''
             for val in ${FIELDS[*]}
             do
                str=$str'IF(CHAR_LENGTH('$val')=0 OR ISNULL('$val'),"NULL",'$val') AS '$val','
             done
             ID='SELECT '$(echo $str|sed 's/,$//')' FROM '$TABLE' WHERE '$ID'\G'
             
             #获取数据
             res=$(${MYSQLPATH}bin/mysql -u${MYSQLUSER} -p${MYSQLPASS}  -D${MYSQLDB}  -e "$ID"|grep -v \*)  #$()|$(())|``|${} 使用方法和区别 里面直接带双引号
             res=$(echo $res|sed 's/ /:/g'|sed 's/::/:/g'|sed "s/[\'$SEP']/$RE_SEP/g")  #处理一下空格
             
             #这里有一点很坑,权限包涵“|”字符,在eval里面它是管道 
             eval $(echo $res | awk -F[:] '{for (k=1;k<=NF;k++) print "upd_arr["k"]="$k}')  #可以直接使用awk编程,很复杂
             
             #循环
             for((k=1;k<=${#upd_arr[*]};k=k+2))
             do
                let val=$k+1                
                
                for key in ${!FIELDS[*]}
                do
                   if [ "${upd_arr[$k]}" == "${FIELDS[$key]}" ];then
                      eval $key=${upd_arr[$val]} #eval 动态变量赋值
                   fi
                done
                
                if [ `expr $val % $(expr ${#FIELDS[*]} \* 2)` == 0 ] && [ $user_k != 'NULL' ];then
                   file=$FTPCONFPATH$user_k
                   if [ "$status_k" != 'ONLINE' ] && [ -f $file ];then 
                      rm -rf $file >/dev/null
                      write_log 't' 'delete conf file '$file' true'
                   fi

                   if [ "$permiss_k" == 'NULL' ];then
                      permiss_k=''
                   fi

                   #生成配置文件更改权限和用户组信息
                   if [ "$status_k" == 'ONLINE' ];then
                      #echo 'write conf'
                      write_conf $user_k $permiss_k
                   fi

                   #权限不存在,不做处理
                   if [ "$allow_ip_k" != 'NULL' ];then
                     write_ip $user_k $allow_ip_k
                     #echo 'write_ip'
                   fi
                fi
             done

         fi

         #得到删除数据  DELETE FROM user WHERE id=2  
         #echo $line |grep "DELETE FROM "$TABLE >/dev/null 
         #if(($?==0));then
          #   RESTART=0
           #  ID=$(echo $line |sed "s/DELETE FROM $TABLE WHERE //" |awk -F[=] '{print $2}')
            # username=$($MYSQLPATH'bin'/mysql -u$MYSQLUSER -p$MYSQLPASS -D$MYSQLDB -e 'SELECT '${FIELDS['user_k']}' FROM '$TABLE' WHERE id='$ID'\G')
             
             #file=$FTPCONFPATH$username
             #if [ -f $file ];then
                #rm -rf $file >/dev/null
              #  if(($?==0));then
               #     write_log 't' 'delete conf file '$file' is true'
                #else
                 #   write_log 'e' 'delete conf file '$file' is false!'
                #fi
             #fi
         #fi
      done
     rm -rf $BINLOGTMP >/dev/null
     
     #重启
     killall vsftpd >/dev/null
     $VSFTPDPATH &

     write_log 't' 'restart vsftpd is true'
   fi
   
   
   注:该脚本配合inotify使用,可以实现及时监控mysql二进制日志,同步配置文件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章