root/branch/ggpolo/umitDB/Search.py @ 1349

Revision 1349, 11.2 kB (checked in by ggpolo, 6 years ago)

Merged with trunk. Removed scripts dir, scheduler_control has been renamed to scheduler-umit and is on root directory now. Treeviews uses single clicks to activate rows now

Line 
1# Copyright (C) 2007 Insecure.Com LLC.
2#
3# Author:  Guilherme Polo <ggpolo@gmail.com>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18# USA
19
20from umitDB.Utils import debug
21from umitDB.Connection import ConnectDB
22from umitDB.Retrieve import CompositeRetrieve
23
24from umitCore.I18N import _
25
26change_text = ( _("change"), _("changes") ) 
27port_text = ( _("port"), _("ports"), _("service") )
28comparison = ( "<", ">", "==", ">=", "<=", "!=" )
29       
30def perform_comparison(ports, compare, decider):
31    """
32    Compare ports against decider using especified comparation.
33    """
34    decider = int(decider)
35   
36    # ports are numbered in ascendent order.
37    for port in ports:
38        if compare == '>':
39            if decider <= port[0]:
40                return True
41        if compare == '<':
42            if decider < port[0]:
43                return False
44            elif decider > port[0]:
45                return True
46        if compare == '!=':
47            if port[0] == decider:
48                return False
49        if compare == '==':
50            if port[0] == decider:
51                return True
52        if compare == '>=':
53            if port[0] >= decider:
54                return True
55        if compare == '<=':
56            if decider < port[0]:
57                if decider == port[0]:
58                    return True
59                return False
60            return True
61           
62    if compare == '!=':
63        return True
64   
65    return False
66
67
68class SearchDB(ConnectDB, CompositeRetrieve):
69    """
70    Performs search on database.
71    """
72   
73    def __init__(self, db):
74        """
75        Expects an umit database.
76        """
77        ConnectDB.__init__(self, db)
78        CompositeRetrieve.__init__(self, self.conn, self.cursor)
79   
80   
81    def search(self, host_id, query):
82        """
83        Convenience method. Performs searches for host_id.
84        """
85        if query.split()[0] in port_text:
86            res = self.port_search(host_id, query)
87            if res:
88                return res
89           
90        #if query.split()[0] in change_text:
91        #    res = self.changes_search(host_id, query)
92        #    if res:
93        #        return res
94           
95        if self.search_for_hostname_for_host_from_db(host_id, query):
96            return _("Hostname")
97       
98        if self.search_for_osmatch_for_host_from_db(host_id, query):
99            return _("OS Match")
100           
101        if self.search_for_osclasses_for_host_from_db(host_id, query):
102            return _("OS Classes")
103       
104        if self.search_for_mac_for_host_from_db(host_id, query):
105            return _("MAC")
106       
107        if self.search_for_fingerprint_for_host_from_db(host_id, query):
108            return _("Fingerprint")
109       
110        # if I'm still here, no results were returned. I will try to do a
111        # port search then. Situation where this may happen:
112        # - Person searching doesnt know about port search syntax, so it does
113        #   a search like "mysql". The correct way would be: "service mysql".
114        res = self.port_search(host_id, port_text[0] + " " + query)
115        if res:
116            return res
117       
118       
119    def port_search(self, host_id, query):
120        """
121        Search for ports for host_id.
122        """
123        debug("Searching under Ports for %s for host_id %d.." % (query, 
124                                                                 host_id))
125        # a port search query is expected to be something like:
126        #  <port_text> <comparison OR Nothing> <something>
127       
128        query = query.split()
129        if len(query) < 2 or (not query[0] in port_text):
130            # bad syntax for port search
131            return None
132       
133        looking_for = query[1]
134        compare = None
135        if len(query) == 3:
136            # assuming second item is a comparion item
137            if query[1] in comparison:
138                # valid comparison especified
139                compare = query[1]
140           
141            looking_for = query[2]
142       
143       
144        results = ''
145        portnumber = False
146        #porttext = False # porttext includes product, version, extrainfo
147        try:
148            int(looking_for)
149            portnumber = True
150        except ValueError:
151            portnumber = False
152            # will perform porttext search
153       
154        if portnumber:
155            # search for port with number in looking_for
156            if compare:
157                self.cursor.execute("SELECT port.portid FROM port \
158                           JOIN _host_port ON (_host_port.fk_port=port.pk) \
159                           WHERE _host_port.fk_host=?", (host_id, ))
160                search = self.cursor.fetchall()
161                search = perform_comparison(search, compare, looking_for)
162
163            else:
164
165                self.cursor.execute("SELECT port.portid FROM port \
166                           JOIN _host_port ON (_host_port.fk_port=port.pk) \
167                           WHERE _host_port.fk_host=? AND \
168                           port.portid LIKE ?", (host_id, '%'+looking_for+'%'))
169                search = self.cursor.fetchall()
170
171            if search:
172                results = _("Port number")
173        else:
174            # search for some text
175            pdata = self.get_portid_and_fks_for_host_from_db(host_id)
176            for pd in pdata:
177                res = self._search_port_text_for_pdata(pd[1], looking_for)
178                if res:
179                    results = res
180                    break
181       
182        return results
183   
184   
185    def _search_port_text_for_pdata(self, service_info_id, query):
186        """
187        """
188        bquery = '%' + query + '%'
189       
190        # Im supposing service name is more likely to be queried than
191        # service info. Also, there is just one field to compare against query
192        # in service_name.
193        service_name = self.cursor.execute("SELECT name FROM service_name \
194                        JOIN service_info ON \
195                        (service_info.fk_service_name=service_name.pk) WHERE \
196                        service_info.pk=? AND name LIKE ?", (service_info_id,
197                                                             bquery)).fetchall()
198        if service_name:
199            return _("Service name")
200       
201        service_info = self.cursor.execute("SELECT product, version, extrainfo \
202                        FROM service_info WHERE service_info.pk=? AND \
203                        (product LIKE ? OR version LIKE ? or \
204                        extrainfo LIKE ?)", (service_info_id, bquery, bquery,
205                                             bquery)).fetchall()
206        if service_info:
207            return _("Service info")
208   
209   
210    def search_for_hostname_for_host_from_db(self, host_id, query):
211        """
212        Search for hostnames like query for host_id.
213        """
214        debug("Searching for hostname %s for host_id %d" % (query, host_id))
215       
216        hostname = self.cursor.execute("SELECT hostname.name FROM hostname \
217                        JOIN _host_hostname ON \
218                        (_host_hostname.fk_hostname=hostname.pk) WHERE \
219                        _host_hostname.fk_host=? AND hostname.name \
220                        LIKE ?", (host_id, '%' + query + '%')).fetchall()
221       
222        if hostname:
223            return True
224       
225                   
226    def search_for_osmatch_for_host_from_db(self, host_id, query):
227        """
228        Search for osmatch like query for host_id.
229        """
230        debug("Searching under OS Match for %s for host_id %d.." % (query, 
231                                                                    host_id))
232       
233        match = self.cursor.execute("SELECT name FROM osmatch WHERE \
234                                     fk_host=? AND name LIKE ?", 
235                                     (host_id, '%' + query + '%')).fetchall()
236        if match:
237            return True
238       
239   
240   
241    def search_for_osclasses_for_host_from_db(self, host_id, query):
242        """
243        Search for osclasses like query for host_id.
244        """
245        debug("Searching under OS Classes for %s for hots_id %d" % (query, 
246                                                                    host_id))
247       
248        bquery = '%' + query + '%'
249       
250        classes = self.cursor.execute("SELECT osclass.accuracy, osgen.gen, \
251                  osfamily.family, osvendor.vendor, ostype.type FROM osclass \
252                  JOIN osgen ON (osclass.fk_osgen = osgen.pk) \
253                  JOIN osfamily ON (osclass.fk_osfamily = osfamily.pk) \
254                  JOIN osvendor ON (osclass.fk_osvendor = osvendor.pk) \
255                  JOIN ostype ON (osclass.fk_ostype = ostype.pk) \
256                  WHERE osclass.fk_host = ? AND (osgen.gen LIKE ? OR \
257                  osfamily.family LIKE ? OR osvendor.vendor LIKE ? OR \
258                  ostype.type LIKE ?)", (host_id, bquery, bquery, 
259                                         bquery, bquery)).fetchall()
260       
261        if classes:
262            return True
263   
264   
265    def search_for_mac_for_host_from_db(self, host_id, query):
266        """
267        Search for MAC like query for host_id.
268        """
269        debug("Searching MAC address like %s for host_id %d" % (query, host_id))
270       
271        fk_address = self.cursor.execute("SELECT fk_address FROM _host_address \
272                                          WHERE fk_host = ?", 
273                                          (host_id, )).fetchall()
274       
275        mac = None
276        for fk in fk_address:
277            mac = self.cursor.execute("SELECT address FROM address WHERE \
278                                       type = 'mac' AND pk = ? AND address \
279                                       LIKE ?", (fk[0], 
280                                                 '%' + query + '%')).fetchone()
281            if mac:
282                return True
283   
284   
285    def search_for_fingerprint_for_host_from_db(self, host_id, query):
286        """
287        Search for query in fingerprint table for host_id.
288        """
289        debug("Searching for Fingerprint info like %s for \
290host_id %d" % (query, host_id))
291       
292        bquery = '%' + query + '%'
293        self.cursor.execute("SELECT tcp_sequence_class, \
294                             tcp_ts_sequence_class, ip_id_sequence_class\
295                             FROM fingerprint_info WHERE fk_host=? AND \
296                             (tcp_sequence_class LIKE ? OR \
297                             tcp_ts_sequence_class LIKE ? OR \
298                             ip_id_sequence_class LIKE ?)", (host_id,
299                                                             bquery, bquery,
300                                                             bquery))
301        fp = self.cursor.fetchall()
302        if fp:
303            return True
304   
Note: See TracBrowser for help on using the browser.