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二進制日誌,同步配置文件。


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