diff --git a/warden3/warden_server/warden_server.py b/warden3/warden_server/warden_server.py index b80951c545c717aa87f2e5cfdef2cd91cae23e7a..11ce067f26d26fa900d86fd80f76adafe0556adf 100755 --- a/warden3/warden_server/warden_server.py +++ b/warden3/warden_server/warden_server.py @@ -193,25 +193,25 @@ class X509Authenticator(NoAuthenticator): def authorize(self, env, client, method, event, args): + # Authorize for debug + if (method == 'getDebug'): + return client if client[0]['debug'] == 1 else None + cl = None service = event['Node'][0]['Name'] + test = 'Test' in event['Category'] - for i in range(len(client)): - if client[i]['service'] == service: - cl = client[i] + for clx in client: + if clx['service'] == service: + cl = clx break if cl is None: return None - # logging.debug(cl) - # logging.debug(method) - # logging.debug(service) - - # return True if (method == 'getEvents' and cl['read']) + # Authorize for sending events if ((method == 'sendEvents' and cl['write'] == 1) or - (method == 'getDebug' and cl['debug'] == 1) or - (method == 'sendEvents' and cl['test'] == 1 and service == 'Test')): + (method == 'sendEvents' and cl['test'] == 1 and test)): return cl return None @@ -275,7 +275,7 @@ class MySQL(Object): def get_client_by_name(self, name): format_strings = ','.join(['%s'] * len(name)) - self.crs.execute("SELECT `id`, `hostname`, `service`, `identity`, `read`, `write`, `debug`, `test` FROM `clients2` WHERE `valid` = 1 AND `hostname` IN (%s)" % format_strings, tuple(name)) + self.crs.execute("SELECT cl.`id`, cl.`hostname`, s.`service`, s.`service_id`, s.`identity`, cl.`read`, s.`write`, s.`test`, cl.`debug` FROM `clients3` cl LEFT JOIN `services` s ON cl.`id` = s.`client_id` WHERE cl.`valid` = 1 AND s.`valid` = 1 AND `hostname` IN (%s)" % format_strings, tuple(name)) row = self.crs.fetchall() return row if row else None @@ -319,17 +319,22 @@ class MySQL(Object): sqlwhere = [] sqltemp = {} - if cat is not None and nocat is not None: raise Error("Unrealizable conditions. Choose cat or nocat option.", 500, method='getEvents', exc=sys.exc_info(), detail={'cat': cat, 'nocat' : nocat}) if cat is not None or nocat is not None: if cat is not None: - sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id IN (%s)", json.loads(cat)) + parent_cats = [] + sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id IN (%s)", json.loads(cat), parent_cats) + for pcats in parent_cats: + sqltemp['cat'] += " %s category_id DIV %s = 1 " % (("OR" if sqltemp['cat'] else ""), pcats) if nocat is not None: - sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id NOT IN (%s)", json.loads(nocat)) - + parent_cats = [] + sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id NOT IN (%s)", json.loads(nocat), parent_cats) + for pcats in parent_cats: + sqltemp['cat'] += " %s category_id DIV %s = 1 " % (("OR" if sqltemp['cat'] else ""), pcats) + sqlwhere.append("e.id IN (SELECT event_id FROM event_category_mapping4 WHERE %s)" % sqltemp['cat']) if tag is not None and notag is not None: @@ -369,12 +374,20 @@ class MySQL(Object): #sqlwhere = sqlwhere[:-4] and_op = "" if not sqlwhere_string else "AND" - # logging.debug("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count))) + logging.debug("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count))) self.crs.execute("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count))) row = self.crs.fetchall() + if row: + maxid = max(r['id'] for r in row) + else: + maxid = self.getLastEventId() + + # logging.debug("MAX ID = %s", str(maxid)) + return { - "lastid": row[-1]['id'] if row else str(id), + "lastid": maxid, + # "lastid": row[-1]['id'] if row else str(id), "events": [row[i]['data'] for i in range(len(row))] } @@ -409,7 +422,31 @@ class MySQL(Object): return errs - def map_id (self, section, key): + def insertLastReceivedId(self, client, id): + logging.debug("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())" % (str(client[0]['id']), id)) + self.crs.execute("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())" % (str(client[0]['id']), id)) + + def getLastEventId(self): + self.crs.execute("SELECT MAX(id) as id FROM events4") + row = self.crs.fetchone() + + return row['id'] if row['id'] is not None else 0 + + def getLastReceivedId(self, client): + logging.debug("IN getLastReceivedId") + client_id = client[0]['id'] + logging.debug("getLastReceivedId (client_id) = %s", str(client_id)) + + logging.debug("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s" % (str(client_id))) + self.crs.execute("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s" % (str(client_id))) + row = self.crs.fetchone() + + logging.debug("getLastReceivedId - %s" % str(row['id'])) + + return row['id'] if row is not None else 0 + + + def map_id (self, section, key, strict = False): # Should by placed in config file data = {} data['Tag'] = { @@ -429,41 +466,51 @@ class MySQL(Object): "Other" : 99 } - data['Category'] = { + data['Category'] = { + "Abusive" : 100, "Abusive.Spam" : 101, "Abusive.Harassment" : 102, "Abusive.Child" : 103, "Abusive.Sexual" : 104, "Abusive.Violence" : 105, + "Malware" : 200, "Malware.Virus" : 201, "Malware.Worm" : 202, "Malware.Trojan" : 203, "Malware.Spyware" : 204, "Malware.Dialer" : 205, "Malware.Rootkit" : 206, + "Recon.Scanning" : 3, "Recon.Scanning" : 301, "Recon.Sniffing" : 302, "Recon.SocialEngineering" : 303, "Recon.Searching" : 304, + "Attempt" : 400, "Attempt.Exploit" : 401, "Attempt.Login" : 402, "Attempt.NewSignature" : 403, + "Intrusion" : 500, "Intrusion.AdminCompromise" : 501, "Intrusion.UserCompromise" : 502, "Intrusion.AppCompromise" : 503, "Intrusion.Botnet" : 504, + "Availability" : 600, "Availability.DoS" : 601, "Availability.DDoS" : 602, "Availability.Sabotage" : 603, "Availability.Outage" : 604, + "Information" : 700, "Information.UnauthorizedAccess" : 701, "Information.UnauthorizedModification" : 702, + "Fraud" : 800, "Fraud.UnauthorizedUsage" : 801, "Fraud.Copyright" : 802, "Fraud.Masquerade" : 803, "Fraud.Phishing" : 804, "Fraud.Scam" : 805, + "Vulnerable" : 900, "Vulnerable.Open" : 901, + "Anomaly" : 1000, "Anomaly.Traffic" : 1001, "Anomaly.Connection" : 1002, "Anomaly.Protocol" : 1003, @@ -477,16 +524,27 @@ class MySQL(Object): try: return data[section][key] except: - return data[section]['Other'] + #Return 0 for strict mode (searching), otherwise map everything else to 'Other' + return 0 if strict else data[section]['Other'] + + +def generateDynamicQuery(self, section, query_string, variables, parent_cats = []): + variables_id = [] + # parent_cats = [] -def generateDynamicQuery(self, section, query_string, variables): - variables_id = [self.map_id(section, v) for v in variables] + for v in variables: + mapped_id = self.map_id(section, v, True) + if mapped_id % 100 != 0: + variables_id.append(mapped_id) + else: + parent_cats.append(mapped_id) + + # variables_id = [self.map_id(section, v) for v in variables if self.map_id(section, v) % 100 != 0] format_strings = ','.join(['\'%s\''] * len(variables_id)) temp_string = query_string % format_strings return temp_string % tuple(variables_id) - def expose(meth): meth.exposed = True return meth @@ -627,6 +685,10 @@ class WardenHandler(Object): @expose def getDebug(self, _env, _client): + auth = self.auth.authorize(_env, _client, 'getDebug', None, None) + if not auth: + raise Error("I'm watching YOU. (Authorization)", 403, method='getDebug', detail={"client": _client}) + return { "environment": _env, "database": self.db.get_debug() @@ -656,6 +718,27 @@ class WardenHandler(Object): except (ValueError, TypeError): id=0 + if id == 0: + try: + id = self.db.getLastReceivedId(_client) + # logging.debug("Last received ID for %s is %s" % (_client['hostname'], str(id))) + except Exception, e: + logging.error(e) + id = 0 + + if id == 0: + try: + id = self.db.getLastEventId() + except Exception as e: + raise Error("Last event id receiving error", 500, detail={"client": _client}) + + self.db.insertLastReceivedId(_client, id) + + return { + "lastid": id, + "events": [] + } + try: count = int(count) except (ValueError, TypeError): @@ -669,6 +752,9 @@ class WardenHandler(Object): logging.info("getEvents(%d, %d, %s, %s, %s, %s, %s, %s): sending %d events" % ( id, count, cat, nocat, tag, notag, group, nogroup, len(res["events"]))) + self.db.insertLastReceivedId(_client, res['lastid']) + logging.debug("lastid inserting: %s" % {'lastid': res['lastid'], 'client' : _client}) + return res