2013-02-14 15:32:17 +04:00
|
|
|
#!/usr/bin/env python
|
2011-09-26 00:36:32 +04:00
|
|
|
|
|
|
|
"""
|
2014-01-13 21:24:49 +04:00
|
|
|
Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/)
|
2011-09-26 00:36:32 +04:00
|
|
|
See the file 'doc/COPYING' for copying permission
|
|
|
|
"""
|
|
|
|
|
|
|
|
import hashlib
|
2012-07-26 17:42:04 +04:00
|
|
|
import os
|
2011-09-26 00:36:32 +04:00
|
|
|
import sqlite3
|
2011-11-22 14:09:35 +04:00
|
|
|
import threading
|
2012-02-27 15:15:53 +04:00
|
|
|
import time
|
2011-09-26 00:36:32 +04:00
|
|
|
|
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
|
2012-12-06 17:14:19 +04:00
|
|
|
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
|
2011-09-26 00:36:32 +04:00
|
|
|
from lib.core.settings import UNICODE_ENCODING
|
2011-09-26 17:36:08 +04:00
|
|
|
from lib.core.threads import getCurrentThreadData
|
2011-11-22 14:09:35 +04:00
|
|
|
from lib.core.threads import getCurrentThreadName
|
2011-09-26 00:36:32 +04:00
|
|
|
|
2011-09-26 17:36:08 +04:00
|
|
|
class HashDB(object):
|
2011-09-26 00:36:32 +04:00
|
|
|
def __init__(self, filepath):
|
2011-09-26 17:36:08 +04:00
|
|
|
self.filepath = filepath
|
2011-11-22 14:09:35 +04:00
|
|
|
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)")
|
|
|
|
except Exception, ex:
|
|
|
|
errMsg = "error occurred while opening a session "
|
|
|
|
errMsg += "file '%s' ('%s')" % (self.filepath, ex)
|
2013-01-04 02:20:55 +04:00
|
|
|
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)
|
2011-09-26 00:36:32 +04:00
|
|
|
|
|
|
|
def close(self):
|
2011-10-25 15:20:42 +04:00
|
|
|
threadData = getCurrentThreadData()
|
2011-09-26 00:36:32 +04:00
|
|
|
try:
|
2011-10-25 15:20:42 +04:00
|
|
|
if threadData.hashDBCursor:
|
|
|
|
threadData.hashDBCursor.close()
|
|
|
|
threadData.hashDBCursor.connection.close()
|
|
|
|
threadData.hashDBCursor = None
|
2011-09-26 00:36:32 +04:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
2011-11-01 23:00:34 +04:00
|
|
|
@staticmethod
|
|
|
|
def hashKey(key):
|
2011-09-26 00:36:32 +04:00
|
|
|
key = key.encode(UNICODE_ENCODING) if isinstance(key, unicode) else repr(key)
|
2014-05-29 11:21:48 +04:00
|
|
|
retVal = int(hashlib.md5(key).hexdigest()[:12], 16)
|
2011-09-26 00:36:32 +04:00
|
|
|
return retVal
|
|
|
|
|
2011-12-28 17:50:03 +04:00
|
|
|
def retrieve(self, key, unserialize=False):
|
2011-09-26 00:36:32 +04:00
|
|
|
retVal = None
|
2012-07-26 17:42:04 +04:00
|
|
|
if key and (self._write_cache or os.path.isfile(self.filepath)):
|
2011-11-01 23:00:34 +04:00
|
|
|
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 ex.message:
|
|
|
|
raise
|
|
|
|
else:
|
|
|
|
break
|
2011-12-28 17:50:03 +04:00
|
|
|
return retVal if not unserialize else unserializeObject(retVal)
|
2011-09-26 00:36:32 +04:00
|
|
|
|
2011-12-28 17:50:03 +04:00
|
|
|
def write(self, key, value, serialize=False):
|
2011-09-26 00:36:32 +04:00
|
|
|
if key:
|
2011-11-01 23:00:34 +04:00
|
|
|
hash_ = HashDB.hashKey(key)
|
2011-11-22 14:09:35 +04:00
|
|
|
self._cache_lock.acquire()
|
2012-04-02 16:58:10 +04:00
|
|
|
self._write_cache[hash_] = getUnicode(value) if not serialize else serializeObject(value)
|
2011-11-22 14:09:35 +04:00
|
|
|
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
|
|
|
|
|
2011-11-22 14:09:35 +04:00
|
|
|
self._cache_lock.acquire()
|
2011-11-22 16:44:28 +04:00
|
|
|
_ = self._write_cache
|
|
|
|
self._write_cache = {}
|
2011-11-22 14:09:35 +04:00
|
|
|
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:
|
2013-02-05 20:04:42 +04:00
|
|
|
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')" % ex.message
|
|
|
|
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
|