sqlmap/lib/utils/hashdb.py

191 lines
6.9 KiB
Python
Raw Normal View History

#!/usr/bin/env python
"""
2016-01-06 02:06:12 +03:00
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""
import hashlib
2012-07-26 17:42:04 +04:00
import os
import sqlite3
import threading
2012-02-27 15:15:53 +04:00
import time
from lib.core.common import getSafeExString
2012-04-02 16:58:10 +04:00
from lib.core.common import getUnicode
2011-12-28 17:50:03 +04:00
from lib.core.common import serializeObject
from lib.core.common import unserializeObject
2012-09-25 13:21:39 +04:00
from lib.core.data import logger
from lib.core.exception import SqlmapDataException
2014-03-24 13:46:23 +04:00
from lib.core.settings import HASHDB_END_TRANSACTION_RETRIES
2012-09-25 13:21:39 +04:00
from lib.core.settings import HASHDB_FLUSH_RETRIES
2011-11-22 14:54:29 +04:00
from lib.core.settings import HASHDB_FLUSH_THRESHOLD
from lib.core.settings import UNICODE_ENCODING
2011-09-26 17:36:08 +04:00
from lib.core.threads import getCurrentThreadData
from lib.core.threads import getCurrentThreadName
2011-09-26 17:36:08 +04:00
class HashDB(object):
def __init__(self, filepath):
2011-09-26 17:36:08 +04:00
self.filepath = filepath
self._write_cache = {}
self._cache_lock = threading.Lock()
2011-09-26 17:36:08 +04:00
def _get_cursor(self):
threadData = getCurrentThreadData()
if threadData.hashDBCursor is None:
2012-11-08 22:16:37 +04:00
try:
connection = sqlite3.connect(self.filepath, timeout=3, isolation_level=None)
threadData.hashDBCursor = connection.cursor()
threadData.hashDBCursor.execute("CREATE TABLE IF NOT EXISTS storage (id INTEGER PRIMARY KEY, value TEXT)")
2015-12-30 15:39:08 +03:00
connection.commit()
2012-11-08 22:16:37 +04:00
except Exception, ex:
errMsg = "error occurred while opening a session "
2016-01-12 12:27:04 +03:00
errMsg += "file '%s' ('%s')" % (self.filepath, getSafeExString(ex))
raise SqlmapDataException(errMsg)
2011-09-26 17:36:08 +04:00
return threadData.hashDBCursor
2014-03-24 13:46:23 +04:00
def _set_cursor(self, cursor):
threadData = getCurrentThreadData()
threadData.hashDBCursor = cursor
cursor = property(_get_cursor, _set_cursor)
def close(self):
2011-10-25 15:20:42 +04:00
threadData = getCurrentThreadData()
try:
2011-10-25 15:20:42 +04:00
if threadData.hashDBCursor:
threadData.hashDBCursor.close()
threadData.hashDBCursor.connection.close()
threadData.hashDBCursor = None
except:
pass
@staticmethod
def hashKey(key):
key = key.encode(UNICODE_ENCODING) if isinstance(key, unicode) else repr(key)
retVal = int(hashlib.md5(key).hexdigest()[:12], 16)
return retVal
2011-12-28 17:50:03 +04:00
def retrieve(self, key, unserialize=False):
retVal = None
2015-10-24 00:48:41 +03:00
2012-07-26 17:42:04 +04:00
if key and (self._write_cache or os.path.isfile(self.filepath)):
hash_ = HashDB.hashKey(key)
2012-08-21 12:28:25 +04:00
retVal = self._write_cache.get(hash_)
2011-11-22 14:54:29 +04:00
if not retVal:
while True:
try:
for row in self.cursor.execute("SELECT value FROM storage WHERE id=?", (hash_,)):
retVal = row[0]
except sqlite3.OperationalError, ex:
if not "locked" in getSafeExString(ex):
2011-11-22 14:54:29 +04:00
raise
2014-12-17 12:02:36 +03:00
except sqlite3.DatabaseError, ex:
2016-01-12 12:27:04 +03:00
errMsg = "error occurred while accessing session file '%s' ('%s'). " % (self.filepath, getSafeExString(ex))
2014-12-17 12:02:36 +03:00
errMsg += "If the problem persists please rerun with `--flush-session`"
raise SqlmapDataException, errMsg
2011-11-22 14:54:29 +04:00
else:
break
2015-10-24 00:48:41 +03:00
if unserialize:
try:
retVal = unserializeObject(retVal)
except:
warnMsg = "error occurred while unserializing value for session key '%s'. " % key
warnMsg += "If the problem persists please rerun with `--flush-session`"
logger.warn(warnMsg)
return retVal
2011-12-28 17:50:03 +04:00
def write(self, key, value, serialize=False):
if key:
hash_ = HashDB.hashKey(key)
self._cache_lock.acquire()
2012-04-02 16:58:10 +04:00
self._write_cache[hash_] = getUnicode(value) if not serialize else serializeObject(value)
self._cache_lock.release()
if getCurrentThreadName() in ('0', 'MainThread'):
self.flush()
2011-11-22 14:54:29 +04:00
def flush(self, forced=False):
2011-11-22 14:41:56 +04:00
if not self._write_cache:
return
2011-11-22 14:54:29 +04:00
if not forced and len(self._write_cache) < HASHDB_FLUSH_THRESHOLD:
return
self._cache_lock.acquire()
2011-11-22 16:44:28 +04:00
_ = self._write_cache
self._write_cache = {}
self._cache_lock.release()
2011-11-22 15:04:43 +04:00
try:
self.beginTransaction()
2011-11-22 16:44:28 +04:00
for hash_, value in _.items():
2012-09-25 13:21:39 +04:00
retries = 0
2011-11-22 15:04:43 +04:00
while True:
2011-10-10 18:23:17 +04:00
try:
2011-11-22 15:04:43 +04:00
try:
self.cursor.execute("INSERT INTO storage VALUES (?, ?)", (hash_, value,))
except sqlite3.IntegrityError:
self.cursor.execute("UPDATE storage SET value=? WHERE id=?", (value, hash_,))
2013-02-12 17:39:21 +04:00
except sqlite3.DatabaseError, ex:
if not os.path.exists(self.filepath):
debugMsg = "session file '%s' does not exist" % self.filepath
logger.debug(debugMsg)
break
2012-09-25 13:21:39 +04:00
if retries == 0:
warnMsg = "there has been a problem while writing to "
warnMsg += "the session file ('%s')" % getSafeExString(ex)
2012-09-25 13:21:39 +04:00
logger.warn(warnMsg)
if retries >= HASHDB_FLUSH_RETRIES:
return
2012-02-27 15:15:53 +04:00
else:
2012-09-25 13:21:39 +04:00
retries += 1
2012-02-27 15:15:53 +04:00
time.sleep(1)
2011-11-22 15:04:43 +04:00
else:
break
finally:
self.endTransaction()
2011-11-02 13:57:42 +04:00
def beginTransaction(self):
2011-11-23 18:26:40 +04:00
threadData = getCurrentThreadData()
if not threadData.inTransaction:
2014-12-05 13:46:03 +03:00
try:
self.cursor.execute("BEGIN TRANSACTION")
except:
# Reference: http://stackoverflow.com/a/25245731
self.cursor.close()
threadData.hashDBCursor = None
self.cursor.execute("BEGIN TRANSACTION")
finally:
threadData.inTransaction = True
2011-11-02 13:57:42 +04:00
def endTransaction(self):
2011-11-23 18:26:40 +04:00
threadData = getCurrentThreadData()
if threadData.inTransaction:
2014-03-24 13:46:23 +04:00
retries = 0
while retries < HASHDB_END_TRANSACTION_RETRIES:
try:
self.cursor.execute("END TRANSACTION")
threadData.inTransaction = False
except sqlite3.OperationalError:
pass
else:
return
retries += 1
time.sleep(1)
2011-12-21 15:50:49 +04:00
try:
2014-03-24 13:46:23 +04:00
self.cursor.execute("ROLLBACK TRANSACTION")
2011-12-22 02:59:23 +04:00
except sqlite3.OperationalError:
2014-03-24 13:46:23 +04:00
self.cursor.close()
self.cursor = None
2011-12-21 15:50:49 +04:00
finally:
threadData.inTransaction = False