root/trunk/umit/core/UmitDB.py @ 4479

Revision 4479, 9.6 kB (checked in by getxsick, 4 years ago)

dict.keys() is no more needed for iterate. fix for #260

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright (C) 2005-2006 Insecure.Com LLC.
5# Copyright (C) 2007-2008 Adriano Monteiro Marques
6#
7# Author: Adriano Monteiro Marques <adriano@umitproject.org>
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23
24try:
25    from hashlib import md5
26except ImportError:
27    # Python 2.4
28    import md5
29
30
31from umit.core.I18N import _
32
33sqlite = None
34OperationalError = None
35try:
36    from pysqlite2 import dbapi2 as sqlite
37    from pysqlite2.dbapi2 import OperationalError
38except ImportError:
39    try:
40        # In case this script is being running under python2.5 with sqlite3
41        import sqlite3 as sqlite
42    except ImportError:
43        raise ImportError(_("""No module named pysqlite2 or sqlite3.
44            Please install pysqlite2 or sqlite3."""))
45    from sqlite3 import OperationalError
46
47from time import time
48
49from umit.core.Paths import Path
50from umit.core.UmitLogging import log
51
52
53umitdb = ""
54
55try:
56    umitdb = Path.umitdb
57except:
58    import os.path
59    from BasePaths import base_paths
60   
61    umitdb = os.path.join(Path.config_dir, base_paths["umitdb"])
62    Path.umitdb = umitdb
63
64
65from os.path import exists, dirname
66from os import access, R_OK, W_OK
67
68
69using_memory = False
70connection = None
71try:
72    connection = sqlite.connect(umitdb)
73except OperationalError:
74    using_memory = True
75    connection = sqlite.connect(":memory:")
76
77# Always return bytestring from the TEXT data type, we will manually handle it.
78try:
79    connection.text_factory = str
80except AttributeError:
81    # XXX text_factory didn't exist prior to pysqlite 2.1.0 and TEXT will
82    # always return a unicode object. Given how Umit handles the situation,
83    # we can't assume this won't cause troubles.
84    pass
85
86
87class Table(object):
88    def __init__(self, table_name):
89        self.table_name = table_name
90        self.table_id = "%s_id" % table_name
91       
92        self.cursor = connection.cursor()
93   
94    def get_item(self, item_name):
95        if self.__getattribute__("_%s" % item_name):
96            return self.__getattribute__("_%s" % item_name)
97
98        sql = "SELECT %s FROM %s WHERE %s_id = %s" % (item_name,
99                                                      self.table_name,
100                                                      self.table_name,
101                                           self.__getattribute__(self.table_id))
102
103        self.cursor.execute(sql)
104       
105        self.__setattr__("_%s" % item_name, self.cursor.fetchall()[0][0])
106        return self.__getattribute__("_%s" % item_name)
107
108    def set_item(self, item_name, item_value):
109        if item_value == self.__getattribute__("_%s" % item_name):
110            return None
111       
112        sql = "UPDATE %s SET %s = ? WHERE %s_id = %s" % (self.table_name,
113                                                         item_name,
114                                                         self.table_name,
115                                           self.__getattribute__(self.table_id))
116        self.cursor.execute(sql, (item_value,))
117        connection.commit()
118        self.__setattr__("_%s" % item_name, item_value)
119
120    def insert(self, **kargs):
121        sql = "INSERT INTO %s ("
122        for k in kargs:
123            sql += k
124            sql += ", "
125        else:
126            sql = sql[:][:-2]
127            sql += ") VALUES ("
128           
129        for v in xrange(len(kargs.values())):
130            sql += "?, "
131        else:
132            sql = sql[:][:-2]
133            sql += ")"
134
135        sql %= self.table_name
136       
137        self.cursor.execute(sql, tuple(kargs.values()))
138        connection.commit()
139
140        sql = "SELECT MAX(%s_id) FROM %s;" % (self.table_name, self.table_name)
141        self.cursor.execute(sql)
142        return self.cursor.fetchall()[0][0]
143
144class UmitDB(object):
145    def __init__(self):
146        self.cursor = connection.cursor()
147
148    def create_db(self):
149        drop_string = ("DROP TABLE scans;",)
150       
151        try:
152            for d in drop_string:
153                self.cursor.execute(d)
154        except:
155            connection.rollback()
156        else:
157            connection.commit()
158
159       
160        creation_string = ("""CREATE TABLE scans (scans_id INTEGER \
161                                                  PRIMARY KEY AUTOINCREMENT,
162                                                  scan_name TEXT,
163                                                  nmap_xml_output TEXT,
164                                                  digest TEXT,
165                                                  date INTEGER)""",)
166
167        for c in creation_string:
168            self.cursor.execute(c)
169            connection.commit()
170
171    def add_scan(self, **kargs):
172        return Scans(**kargs)
173
174    def get_scans_ids(self):
175        sql = "SELECT scans_id FROM scans;"
176        self.cursor.execute(sql)
177        return [sid[0] for sid in self.cursor.fetchall()]
178
179    def get_scans(self):
180        scans_ids = self.get_scans_ids()
181        for sid in scans_ids:
182            yield Scans(scans_id=sid)
183
184    def cleanup(self, save_time):
185        log.debug(">>> Cleanning up data base.")
186        log.debug(">>> Removing results olders than %s seconds" % save_time)
187        self.cursor.execute("SELECT scans_id FROM scans WHERE date < ?",
188                            (time() - save_time,))
189       
190        for sid in [sid[0] for sid in self.cursor.fetchall()]:
191            log.debug(">>> Removing results with scans_id %s" % sid)
192            self.cursor.execute("DELETE FROM scans WHERE scans_id = ?", (sid, ))
193        else:
194            connection.commit()
195            log.debug(">>> Data base sucessfully cleanned up!")
196       
197
198class Scans(Table, object):
199    def __init__(self, **kargs):
200        Table.__init__(self, "scans")
201        if "scans_id" in kargs:
202            self.scans_id = kargs["scans_id"]
203        else:
204            log.debug(">>>Ceating new scan result entry at data base")
205            fields = ["scan_name", "nmap_xml_output", "date"]
206           
207            for k in kargs:
208                if k not in fields:
209                    raise Exception("Wrong table field passed to creation \
210method. '%s'" % k)
211
212            if "nmap_xml_output" not in kargs or \
213               not kargs["nmap_xml_output"]:
214                raise Exception("Can't save result without xml output")
215
216            if not self.verify_digest(md5.new(kargs["nmap_xml_output"]).\
217                                      hexdigest()):
218                raise Exception("XML output registered already!")
219           
220            self.scans_id = self.insert(**kargs)
221
222    def verify_digest(self, digest):
223        self.cursor.execute("SELECT scans_id FROM scans WHERE digest = ?",
224                            (digest, ))
225        result = self.cursor.fetchall()
226        if result:
227            return False
228        return True
229
230    def add_host(self, **kargs):
231        kargs.update({self.table_id:self.scans_id})
232        return Hosts(**kargs)
233
234    def get_hosts(self):
235        sql = "SELECT hosts_id FROM hosts WHERE scans_id= %s" % self.scans_id
236       
237        self.cursor.execute(sql)
238        result = self.cursor.fetchall()
239       
240        for h in result:
241            yield Hosts(hosts_id=h[0])
242
243    def get_scans_id(self):
244        return self._scans_id
245
246    def set_scans_id(self, scans_id):
247        if scans_id != self._scans_id:
248            self._scans_id = scans_id
249
250    def get_scan_name(self):
251        return self.get_item("scan_name")
252
253    def set_scan_name(self, scan_name):
254        self.set_item("scan_name", scan_name)
255
256    def get_nmap_xml_output(self):
257        return self.get_item("nmap_xml_output")
258
259    def set_nmap_xml_output(self, nmap_xml_output):
260        self.set_item("nmap_xml_output", nmap_xml_output)
261        self.set_item("digest", md5.new(nmap_xml_output).hexdigest())
262
263    def get_date(self):
264        return self.get_item("date")
265
266    def set_date(self, date):
267        self.set_item("date", date)
268   
269    scans_id = property(get_scans_id, set_scans_id)
270    scan_name = property(get_scan_name, set_scan_name)
271    nmap_xml_output = property(get_nmap_xml_output, set_nmap_xml_output)
272    date = property(get_date, set_date)
273   
274    _scans_id = None
275    _scan_name = None
276    _nmap_xml_output = None
277    _date = None
278
279
280######################################################################
281# Verify if data base exists and if it does have the required tables.
282# If something is wrong, re-create table
283def verify_db():
284    cursor = connection.cursor()
285    try:
286        cursor.execute("SELECT scans_id FROM scans WHERE date = 0")
287    except sqlite.OperationalError:
288        u = UmitDB()
289        u.create_db()
290verify_db()
291
292######################################################################
293
294if __name__ == "__main__":
295    from pprint import pprint
296    import psyco
297    psyco.profile()
298   
299    u = UmitDB()
300
301    #print "Creating Data Base"
302    #u.create_db()
303
304    #print "Creating new scan"
305    #s = u.add_scan(scan_name="Fake scan", nmap_xml_output="", date="007")
306
307    #s = Scans(scans_id=2)
308    #print s.scans_id
309    #print s.scan_name
310    #print s.nmap_xml_output
311    #print s.date
312   
313    sql = "SELECT * FROM scans;"
314    u.cursor.execute(sql)
315    print "Scans:",
316    pprint(u.cursor.fetchall())
Note: See TracBrowser for help on using the browser.