ogftLdZdZdZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z ddl mZdd lmZdd lmZd d lmZmZmZeeZd Zej4dk\rdZdZn dZdZdZej<eeej@dedZ!Gdde"Z#y)zSteven Hiscocksz"Copyright (c) 2013 Steven HiscocksGPLNwraps)RLock)MyTime) FailTicket)Utils) getLogger uni_string PREFER_ENCcNt|tr t|}t|S)z/Avoid errors on types unknown in json-adapters.) isinstancesetlistr )xs :/usr/lib/python3/dist-packages/fail2ban/server/database.py _json_defaultr*sq# 1g!1 )c tj|dtjtd}|S#t $r:}t jd|t jdkd}Yd}~|Sd}~wwxYw)NF ensure_asciidefaultreplacejson dumps failed: %rexc_info{}) jsondumpsrencoder ExceptionlogSyserrorgetEffectiveLevelres r_json_dumps_safer+1sn  zz!%?FF 1 (   <<'V5M5M5OST5T<U 1 (  s04 A7/A22A7c tj|jtd}|S#t$r:}t j d|t jdki}Yd}~|Sd}~wwxYwNrzjson loads failed: %rrrr"loadsdecoderr%r&r'r(r)s r_json_loads_safer1;e  zz!((:y121 (   <<'V5M5M5OST5T<U 1 (  )- A0/A++A0ct|tr td|jDSt|ttfr|Dcgc] }t |c}St|t r)|jtdjtSt|t r|jtdS|Scc}w)Nc3NK|]\}}t|t|fywN) _normalize).0kvs r z_normalize..Fs!D$!Q 1 z!}-Ds#%r) rdictitemsrrr7strr$rr0)relements rr7r7Ds4 D!'')D DD!dC[!./ 07:g  00!S ((:y ) 0 0 <<!S ((:y )) ( 1s Cc tjt|dt}|S#t$r:}t j d|t jdkd}Yd}~|Sd}~wwxYw)NFrrrrr!)r"r#r7rr%r&r'r(r)s rr+r+Psb  zz*Q-e]K1 (   <<'V5M5M5OST5T<U 1 (  s%) A,/A''A,c tj|jtd}|S#t$r:}t j d|t jdki}Yd}~|Sd}~wwxYwr-r.r)s rr1r1Yr2r3JSONc.tfd}|S)Nc:|j5|j5|jj} ||g|i||jcdddcdddS#|jwxYw#1swYnxYw dddy#1swYyxYwr6)_lock_dbcursorclose)selfargskwargscurfs rwrapperz"commitandrollback..wrappergs zz  ((// C dC )$ )& )YY[   YY[ s9 BA; A&A; B&A88A;;B BBr)rMrNs` rcommitandrollbackrOfs (  rceZdZdZdZdZeeZd'dZd(dZ dZ e dZ dZ e d Ze d Zej d Zd(d Zed(d ZdZedZedZedZedZed)dZedZd*dZed)dZedZdZed*dZedZ edZ!edZ"ed+dZ#dZ$d+d Z%ed,d!Z&d,d"Z' d-d#Z(d$Z)d%Z*ed&Z+y). Fail2BanDbaFail2Ban database for storing persistent data. This allows after Fail2Ban is restarted to reinstated bans and to continue monitoring logs from the same point. This will either create a new Fail2Ban database, connect to an existing, and if applicable upgrade the schema in the process. Parameters ---------- filename : str File name for SQLite3 database, which will be created if doesn't already exist. purgeAge : int Purge age in seconds, used to remove old bans from database during purge. Raises ------ sqlite3.OperationalError Error connecting/creating a SQLite3 database. RuntimeError If exisiting database fails to update to new schema. Attributes ---------- filename purgeage r)) fail2banDbz7CREATE TABLE IF NOT EXISTS fail2banDb(version INTEGER);)jailszCREATE TABLE IF NOT EXISTS jails(name TEXT NOT NULL UNIQUE, enabled INTEGER NOT NULL DEFAULT 1);CREATE INDEX IF NOT EXISTS jails_name ON jails(name);)logsaSCREATE TABLE IF NOT EXISTS logs(jail TEXT NOT NULL, path TEXT, firstlinemd5 TEXT, lastfilepos INTEGER DEFAULT 0, FOREIGN KEY(jail) REFERENCES jails(name) ON DELETE CASCADE, UNIQUE(jail, path),UNIQUE(jail, path, firstlinemd5));CREATE INDEX IF NOT EXISTS logs_path ON logs(path);CREATE INDEX IF NOT EXISTS logs_jail_path ON logs(jail, path);)bansaCREATE TABLE IF NOT EXISTS bans(jail TEXT NOT NULL, ip TEXT, timeofban INTEGER NOT NULL, bantime INTEGER NOT NULL, bancount INTEGER NOT NULL default 1, data JSON, FOREIGN KEY(jail) REFERENCES jails(name) );CREATE INDEX IF NOT EXISTS bans_jail_timeofban_ip ON bans(jail, timeofban);CREATE INDEX IF NOT EXISTS bans_jail_ip ON bans(jail, ip);CREATE INDEX IF NOT EXISTS bans_ip ON bans(ip);)bipsaZCREATE TABLE IF NOT EXISTS bips(ip TEXT NOT NULL, jail TEXT NOT NULL, timeofban INTEGER NOT NULL, bantime INTEGER NOT NULL, bancount INTEGER NOT NULL default 1, data JSON, PRIMARY KEY(ip, jail), FOREIGN KEY(jail) REFERENCES jails(name) );CREATE INDEX IF NOT EXISTS bips_timeofban ON bips(timeofban);CREATE INDEX IF NOT EXISTS bips_ip ON bips(ip);czd|_t|_||_||_||_|j y)N ) maxMatchesrrE _dbFilename _purgeAge_outDatedFactor _connectDB)rIfilenamepurgeAgeoutDatedFactors r__init__zFail2BanDb.__init__s3$/w$*$$.'$//rc p|j} tj|dtj|_i|_t jd| ddl }d}|jj} |jd|jd|s|jd |jd |jd |jd}|t j"k7rm|j%|}|t j"k(rt j'd ||n1t jd t j"||t)d|rt j9d|j;|dt j9dt j9d|jd|j=D]'} t j9ddj?| )|jjA|r$|r|jd |j5yy#tj$r*}t jd||jdd}~wwxYw#t$rd}Y3wxYw#tj$r(t j'd|j+Yltj,$rq}t jd||jdt.j0j3|s|j5d}|j7Yd}~d}~wwxYw#|rt j9d|j;|dt j9dt j9d|jd|j=D]'} t j9ddj?| )|jjA|r$|r|jd |j5wwxYw)NF)check_same_thread detect_typesz.Connected to fail2ban persistent database '%s'z9Error connecting to fail2ban persistent database '%s': %srTzPRAGMA foreign_keys = ONzPRAGMA synchronous = OFFzPRAGMA journal_mode = MEMORYzPRAGMA temp_store = MEMORY&SELECT version FROM fail2banDb LIMIT 1z"Database updated from '%r' to '%r'zIDatabase update failed to achieve version '%r': updated from '%r' to '%r'zFailed to fully updatez"New database created. Version '%r'z3Error opening fail2ban persistent database '%s': %sz# Create missing tables/indices ...) incrementalz -> okz Check integrity ...zPRAGMA integrity_checkz -> %s )!rZsqlite3connectPARSE_DECLTYPESrF_bansMergedCacher&infoOperationalErrorr'rJ__pypy__ ImportErrorrGexecutefetchonerQ __version__updateDbwarning RuntimeErrorcreateDbErrorospathisfilerHrepairDBdebug _createDbfetchalljoincommit) rIcheckIntegrityr^r*rnpypyrLversion newversionss rr]zFail2BanDb._connectDBsI   ( oo ((*48 4 ;;4h@ 4 #3;;)*;;)* KK./;;+,;;78 \\^A 7 '''w'JZ+++ ^^9 z \\$gz3 0 11 LL67NN3DN) LL LL()KK() \\^* \\)SXXa[)*HHOO  [[/0IIK  }  ! !  <<? affQi    4  ! ! >>6MMO   <<9 affQi ''.. " 99; 3==?? 0 LL67NN3DN) LL LL()KK() \\^* \\)SXXa[)*HHOO  [[/0IIK  sjAIJ8AJBMI?%I::I? JJ7M MM A&M M MMC!P5ctjd|jjtj dy)Nz Close connection to database ...zConnection to database closed.)r&r|rFrHrlrIs rrHzFail2BanDb.closes*,,12((..++./rc |jS#t$rL|jdztjdt j z|_|jcYSwxYw)N.z %Y%m%d-%H%M%S)_Fail2BanDb__dbBackupFilenameAttributeErrorrZtimestrftimergmtimers r_dbBackupFilenamezFail2BanDb._dbBackupFilename#s["  ! !! "!--3dmmOU[UbUbUd6ee4  ! !!"s AA#"A#c Gddt}|j}d|_ tjd|jt j j|jsKtj|j|jtjd|jnHt j j|jrt j|jtjd|j|jft j|jj}|r)tjd||j!dntjd ||d  ||_y#t$r}tj#d |j|j$d t'|| xrtj)d kt j|j|j!dYd}~d}~wwxYw#||_wxYw)Nc eZdZy),Fail2BanDb.repairDB..RepairExceptionN)__name__ __module__ __qualname__rrRepairExceptionr,srrzTrying to repair database %s Database backup created: %szHf2b_db=$0; f2b_dbbk=$1; sqlite3 "$f2b_dbbk" ".dump" | sqlite3 "$f2b_db" z5 Repair seems to be successful, restored %d byte(s).T)rz1 Repair seems to be failed, restored %d byte(s).z Recreate ...z/ Error repairing of fail2ban database '%s': %srrXr)r%r{r&rlrZrxryrzrshutilmoveremover executeCmdstatst_sizer]r'rJrr()rIr _repairDB dbFileSizer*s rr{zFail2BanDb.repairDB+s mm)$- ;;-t/?/?@ ''..// 0 KK  $"8"89 KK/1G1GH t''(IIddd,,./(()11: KKGTOO4O( KKCZP . )))4= ( <<AaffQiQ00UV5M5M5OSU5UX99T  ??$?'' (4=s1E:F'I' H?0BH:5I:H??I I c|jS)z&File name of SQLite3 database file. )rZrs rr^zFail2BanDb.filenameNs   rc|jS)zPurge age in seconds. )r[rs rpurgeagezFail2BanDb.purgeageTs rc8tj||_yr6)r str2secondsr[)rIvalues rrzFail2BanDb.purgeageZs%%e,$.rctjD]\}}|j||jdtjf|jd|j dS)z8Creates a new database, called during initialisation. z\INSERT INTO fail2banDb(version) SELECT ? WHERE NOT EXISTS (SELECT 1 FROM fail2banDb LIMIT 1)rer)rQ_CREATE_SCRIPTS executescriptrprrrq)rIrLrfnrs rr}zFail2BanDb._createDb^sk**fq!Q++C++67  rc&|j||Sr6)r})rIrLrfs rrvzFail2BanDb.createDbks [ ))rc^|jd|f|j}|duxr|dS)NzQselect 1 where exists (select 1 from sqlite_master WHERE type='table' AND name=?)r)rprq)rIrLtableress r _tableExistszFail2BanDb._tableExistsos8++@BGK # D #SV#rc4|tjkDr td tj d|j |t jj|j sJtj|j|j tj d|j |dkr7|j|dr%|jdtjdz|dkr7|j|dr%|jd tjdz|d krZ|j|d sH|jd tjd z|j|dr|jd |jd|j!dS#t"$r_}tj%d|j&|j(dtj+dk|j-Yd}~yd}~wwxYw)zUpdate an existing database, called during initialisation. A timestamped backup is also created prior to attempting the update. zIAttempt to travel to future version of database ...how did you get here??z&Upgrade database: %s from version '%r'rr rTzBEGIN TRANSACTION;CREATE TEMPORARY TABLE logs_temp AS SELECT * FROM logs;DROP TABLE logs;%s;INSERT INTO logs SELECT * from logs_temp;DROP TABLE logs_temp;UPDATE fail2banDb SET version = 2;COMMIT;rrUzBEGIN TRANSACTION;CREATE TEMPORARY TABLE bans_temp AS SELECT jail, ip, timeofban, -2 as bantime, 1 as bancount, data FROM bans;DROP TABLE bans;%s; INSERT INTO bans SELECT * from bans_temp;DROP TABLE bans_temp;COMMIT;rrVz?BEGIN TRANSACTION;%s; UPDATE fail2banDb SET version = 4;COMMIT;zINSERT OR REPLACE INTO bips(ip, jail, timeofban, bantime, bancount, data) SELECT ip, jail, timeofban, bantime, bancount, data FROM bans order by timeofbanrerz#Failed to upgrade database '%s': %srXrN)rQrrNotImplementedErrorr&rlrrxryrzrcopyfiler^rr _CREATE_TABSrprqr%r'rZrJr(r{)rIrLrr*s rrszFail2BanDb.updateDbus  z%%% Q SS* ;;79O9OQXY ''..// 0 OODMM4#9#9: KK/1G1GH kd''V4**6234kd''V4 **62 34k$++C8**6234 f%[[\];;78 ,,.   <<5affQi  % % '2 -/==?? sFF// H8AHHc|jd|jf|jdkr|jd|jfyy)zmAdds a jail to the database. Parameters ---------- jail : Jail Jail to be added to the database. z7INSERT OR IGNORE INTO jails(name, enabled) VALUES(?, 1)rz|jd|jfy)zvDeletes a jail from the database. Parameters ---------- jail : Jail Jail to be removed from the database. z'UPDATE jails SET enabled=0 WHERE name=?N)rprrs rdelJailzFail2BanDb.delJails++,tyym=rc&|jdy)z'Deletes all jails from the database. zUPDATE jails SET enabled=0NrprIrLs r delAllJailszFail2BanDb.delAllJailss ++*+rNc||jdn|jdt|td|jDS)zGet name of jails in database. Currently only used for testing purposes. Returns ------- set Set of jail names. zSELECT name FROM jailsz%SELECT name FROM jails WHERE enabled=c3&K|] }|d ywrNrr8rows rr;z*Fail2BanDb.getJailNames.. /SV /)rpintr fetchmany)rIrLenableds r getJailNameszFail2BanDb.getJailNamessE _;;'(;;\ /s}} / //rc|j|||j|j|jS)a7Adds a log to the database. Parameters ---------- jail : Jail Jail that log is being monitored by. container : FileContainer File container of the log file being added. Returns ------- int If log was already present in database, value of last position in the log file; else `None` )_addLog getFileNamegetPosgetHashrIrLr containers raddLogzFail2BanDb.addLogs6" c4!6!6!8):J:J:LiN_N_Na bbrcd}|jd|j|f |j\}}|$|s| |jd|j|||f|||k7rd}|S#t$rd}Y>wxYw)NzBSELECT firstlinemd5, lastfilepos FROM logs WHERE jail=? AND path=?UINSERT OR REPLACE INTO logs(jail, path, firstlinemd5, lastfilepos) VALUES(?, ?, ?, ?))rprrq TypeError)rIrLrrposmd5 lastLinePos firstLineMD5s rrzFail2BanDb._addLogs+++IIt"||~<sco;;!YYc379 _ ,;  <sA&& A43A4cd}g}| |dz }|j|j|j||td|j DS)zGets all the log paths from the database. Currently only for testing purposes. Parameters ---------- jail : Jail If specified, will only reutrn logs belonging to the jail. Returns ------- set Set of log paths. zSELECT path FROM logsz WHERE jail=?c3&K|] }|d ywrrrs rr;z)Fail2BanDb.getLogPaths..rr)appendrrprr)rIrLrquery queryArgss r getLogPathszFail2BanDb.getLogPathssU "%) O5 DII++eY /s}} / //rc|j|||j|j|jy)zUpdates hash and last position in log file. Parameters ---------- jail : Jail Jail of which the log file belongs to. container : FileContainer File container of the log file being updated. N) _updateLogrrrrs r updateLogzFail2BanDb.updateLogs3//#tY224i6F6F6H)J[J[J]^rc|jd|||j|f|js!|jd|j|||fyy)NzEUPDATE logs SET firstlinemd5=?, lastfilepos=? WHERE jail=? AND path=?rr)rIrLrrrrs rrzFail2BanDb._updateLog,sR++ #S$))T:< ;;!YYc379 rc,|j|||||S)aAGet journal position from database. Parameters ---------- jail : Jail Jail of which the journal belongs to. name, time, iso : Journal name (typically systemd-journal) and last known time. Returns ------- int (or float) Last position (as time) if it was already present in database; else `None` )rrIrLrrrisos r getJournalPoszFail2BanDb.getJournalPos6s c4tS 11rc.|j|||||y)zUpdates last position (as time) of journal. Parameters ---------- jail : Jail Jail of which the journal belongs to. name, time, iso : Journal name (typically systemd-journal) and last known time. N)rrs r updateJournalzFail2BanDb.updateJournalHs//#tT4-rc t|j} |j||f= |j|df=|j }|j d}|j r>|rQt||j kDr9|j}||j d|d<n|r|j}|d=|jd|j|tt|j|j|jj|j!|f|jd||jtt|j|j|jj|j!|fy#t$rYwxYw#t$rYwxYw)zAdd a ban to the database. Parameters ---------- jail : Jail Jail in which the ban has occurred. ticket : BanTicket Ticket of the ban to be added. NmatcheszWINSERT INTO bans(jail, ip, timeofban, bantime, bancount, data) VALUES(?, ?, ?, ?, ?, ?)zbINSERT OR REPLACE INTO bips(ip, jail, timeofban, bantime, bancount, data) VALUES(?, ?, ?, ?, ?, ?))r>getIDrkKeyErrorgetDatagetrYlencopyrprrroundgetTime getBanTimeactions getBanCount)rIrLrticketipdatars raddBanzFail2BanDb.addBanUs 6<<>" b$Z( b$Z(  $ HHY ' __ #g,0 99;Dt./0DO ))+4 I++\IIr3uV^^-./1B1B4<)rIrLrrJquery1query2rrs rdelBanzFail2BanDb.delBan|s -& ,&yyk) T;;vy!;;vy! M&M& 2 #bb'9Q<;;vy!;;vy!#rc4d}g}| |dz }|j|j|0|dk\r+|dz }|jtj|z ||dz }|jt ||dz }t |j ||S)Nz,SELECT ip, timeofban, data FROM bans WHERE 1 AND jail=?r AND timeofban > ? AND ip=?z ORDER BY ip, timeofban desc)rrrrr>rrp)rIrLrbantimerrrs r_getBanszFail2BanDb._getBanss 8%) M5 DII W\  5 FKKMG+,^K5 CG ))% ckk%+ ,,rc g}|jdi|D]5\}}}|jt|||dj|7|S)aGet bans from the database. Parameters ---------- jail : Jail Jail that the ban belongs to. Default `None`; all jails. bantime : int Ban time in seconds, such that bans returned would still be valid now. Negative values are equivalent to `None`. Default `None`; no limit. ip : str IP Address to filter bans by. Default `None`; all IPs. Returns ------- list List of `Ticket`s for bans stored in database. r)rrr setData)rIrKticketsr timeofbanrs rgetBanszFail2BanDb.getBanssY& '*T]]4V4b)T >>*R+, 2;t .rc |j5d}||dkr*||f}||jvr|j|cdddSg}d}t|j|||}|r|dd}g} d} i} |D]\} } }| |k7r7t || }|j | |j || }g} d} i} |jdg}|jt| z }|dkDrt||kr|| z} n || d| z} | |jddz } | |d<| |d<| j|| }t  | }|j ||r||n||j|<||n|cdddS#1swYyxYw)a}Get bans from the database, merged into single ticket. This is the same as `getBans`, but bans merged into single ticket. Parameters ---------- jail : Jail Jail that the ban belongs to. Default `None`; all jails. bantime : int Ban time in seconds, such that bans returned would still be valid now. Negative values are equivalent to `None`. Default `None`; no limit. ip : str IP Address to filter bans by. Default `None`; all IPs. Returns ------- list or Ticket Single ticket representing bans stored in database per IP in a list. When `ip` argument passed, a single `Ticket` is returned. Nr)rrrrfailuresrr) rErkrrr setAttemptrrrYrupdate)rIrrrcacheKeyr rresults prev_baniprrtickdatabanipr rprev_timeofbanmmaxadds r getBansMergedzFail2BanDb.getBansMergeds0 zz-,8 o1DzH4(((  ! !( + -,-,7 6 $--2D'-B C7 AJGHH") y$ *ng>f ! nnVjghh )R QooG ,V Q6 WwF78w&w *a((X T*T)_ __T^/ 0~H =F NN613gD(#Z'V[-,-,-,s*E:D/E::FcPt|}|sd}nd}|dz }|g}|s"| |dz }|j|j|+|dz }|jtj|z ||dz }|j||s||dz }t |j ||S)Nz-SELECT bancount, timeofban, bantime FROM bipsz