crunchtools 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. crunchtools/CrunchLog.py +793 -0
  2. crunchtools/Filter.py +73 -0
  3. crunchtools/LogGraph.py +543 -0
  4. crunchtools/LogHash.py +408 -0
  5. crunchtools/ScriptLog.py +241 -0
  6. crunchtools/__init__.py +51 -0
  7. crunchtools/api.py +122 -0
  8. crunchtools/cli.py +463 -0
  9. crunchtools/data/filters/daemon.stopwords +6 -0
  10. crunchtools/data/filters/hash.stopwords +10 -0
  11. crunchtools/data/filters/host.stopwords +1 -0
  12. crunchtools/data/filters/words.stopwords +204 -0
  13. crunchtools/data/fingerprint_library/fedora11-reboot-dell.fp +650 -0
  14. crunchtools/data/fingerprint_library/rhel4-reboot-dl380.fp +654 -0
  15. crunchtools/data/fingerprint_library/rhel4-reboot-vmware.fp +309 -0
  16. crunchtools/data/fingerprint_library/rhel5-reboot-dl380.fp +336 -0
  17. crunchtools/data/fingerprint_library/rhel5-reboot-vmware.fp +268 -0
  18. crunchtools/data/fingerprint_library/ubuntu10.04-reboot-kvm.fp +330 -0
  19. crunchtools/data/fingerprint_library/ubuntu9.04-reboot-vmware.fp +359 -0
  20. crunchtools/data/fingerprints/fedora11-reboot.fp +650 -0
  21. crunchtools/data/fingerprints/rhel4-reboot.fp +966 -0
  22. crunchtools/data/fingerprints/rhel5-reboot.fp +604 -0
  23. crunchtools/data/fingerprints/ubuntu10.04-reboot.fp +330 -0
  24. crunchtools/data/fingerprints/ubuntu9.04-reboot.fp +359 -0
  25. crunchtools/errors.py +28 -0
  26. crunchtools/resources.py +58 -0
  27. crunchtools-2.1.0.dist-info/METADATA +165 -0
  28. crunchtools-2.1.0.dist-info/RECORD +31 -0
  29. crunchtools-2.1.0.dist-info/WHEEL +4 -0
  30. crunchtools-2.1.0.dist-info/entry_points.txt +2 -0
  31. crunchtools-2.1.0.dist-info/licenses/COPYING +624 -0
@@ -0,0 +1,793 @@
1
+ """
2
+ Generic log class which contains a payload of objects which conform to the
3
+ LogEntry specification. Log, which is a List (array) of type LogEntry, is
4
+ relied upon and consumed to build any of the XHash objects such as SuperHash
5
+ or GraphHash.
6
+ """
7
+
8
+ from collections import UserList
9
+
10
+ import re
11
+ import sys
12
+ import logging
13
+ from .errors import EmptyLogError, ParseError
14
+ from random import choice
15
+ import datetime
16
+ import time
17
+ import types
18
+ #import rpdb2; rpdb2.start_embedded_debugger("password")
19
+
20
+
21
+ # Bound on how many times select() will resample before giving up and
22
+ # using RawEntry. Without a bound, input that no driver claims spins forever.
23
+ MAX_SELECT_ROUNDS = 5
24
+
25
+
26
+ class Tally():
27
+
28
+ matrix = {}
29
+ tally_threshold = 0
30
+
31
+ def __init__(self, entry_types, max_sample_lines):
32
+
33
+ self.matrix = {}
34
+ self.max_sample_lines = max_sample_lines
35
+ self.tally_threshold = max_sample_lines / 4
36
+
37
+ for entry_type in entry_types:
38
+ self.matrix[entry_type] = 0
39
+
40
+ def append(self, entry_type):
41
+ self.matrix[entry_type] += 1
42
+
43
+ def is_type(self, entry_type):
44
+
45
+ # Setup the correct tally logic method
46
+ tally_logic = entry_type.tally_logic
47
+
48
+ m = self.matrix[entry_type]
49
+ th = self.tally_threshold
50
+ msl = self.max_sample_lines
51
+
52
+ if tally_logic(m, th, msl):
53
+ return True
54
+ else:
55
+ return False
56
+
57
+
58
+ class CrunchLog(UserList):
59
+ """
60
+ Class which extends UserList to provide robust in memory log object
61
+ """
62
+
63
+ def __init__(self, filename=""):
64
+ UserList.__init__(self)
65
+
66
+ if filename == "":
67
+ return
68
+
69
+ if filename == "__none__":
70
+ buf = sys.stdin.readlines()
71
+ else:
72
+ logging.debug("Opening File: %s", filename)
73
+ with open(filename) as handle:
74
+ buf = handle.readlines()
75
+
76
+ self._build(buf, filename)
77
+
78
+ @classmethod
79
+ def from_text(cls, text, source_name="<text>"):
80
+ """Build a log from a string already in memory.
81
+
82
+ The reason this exists: every caller that is not a shell has its
83
+ payload in memory already, and the file-only constructor forced it
84
+ through a temporary file to use this library at all.
85
+ """
86
+ log = cls()
87
+ log._build(text.splitlines(keepends=True), source_name)
88
+ return log
89
+
90
+ def _build(self, buf, source_name):
91
+ """Select a driver for the buffer and parse every line with it."""
92
+ if len(buf) < 1:
93
+ raise EmptyLogError("no data found in " + (source_name or "input"))
94
+
95
+ # Automatically select entry type
96
+ self.Entry = self.select(buf)
97
+
98
+ # Save for introspective purpose
99
+ self.payload_type = self.Entry.__name__
100
+ self.file_name = source_name
101
+ self.build_date = datetime.datetime.now()
102
+
103
+ # Build from entry type
104
+ counter = 0
105
+ for line in buf:
106
+ try:
107
+ self.append(self.Entry(line))
108
+ counter += 1
109
+ except (ValueError, TypeError) as exc:
110
+ raise ParseError(counter, line) from exc
111
+
112
+ def select(self, buf):
113
+ """
114
+ Determines which type of entry to use when building CrunchLog by
115
+ by sampling the buffer and using a quarum based on votes for each
116
+ log type
117
+ """
118
+
119
+ sample_lines = []
120
+ max_sample_lines = 10
121
+ t = Tally(entry_types, max_sample_lines)
122
+
123
+ if len(buf) < 1:
124
+ return RawEntry
125
+
126
+ # This loop used to be `while (1)`, which never terminated when no
127
+ # driver reached quorum — and sample_lines grew on every pass, so it
128
+ # burned memory while it span. A buffer of blank lines does exactly
129
+ # that: `choice(buf).split()` yields [], and every is_type() rejects
130
+ # an empty list, RawEntry's included, so nothing ever votes.
131
+ #
132
+ # Resampling more than a few times means the buffer is not giving a
133
+ # clear answer, and more rounds will not change that. Cap it and fall
134
+ # back to RawEntry, which is what the registry already appoints as the
135
+ # last resort.
136
+ for _ in range(MAX_SELECT_ROUNDS):
137
+
138
+ # Get X number of samples
139
+ for i in range(0, max_sample_lines):
140
+ sample_lines.append(choice(buf).split())
141
+
142
+ # Build tallies for the collected samples
143
+ for line in sample_lines:
144
+ for entry_type in entry_types:
145
+ if entry_type.is_type(line):
146
+ t.append(entry_type)
147
+ break
148
+
149
+ # Tally logic is determined by driver
150
+ for entry_type in entry_types:
151
+ if t.is_type(entry_type):
152
+ logging.info("Determined %s: %s", entry_type.__name__, t.matrix[entry_type])
153
+
154
+ return entry_type
155
+
156
+ logging.info("No driver reached quorum after %d rounds; using RawEntry",
157
+ MAX_SELECT_ROUNDS)
158
+ return RawEntry
159
+
160
+ def contains(self, obj):
161
+ """Determine what kind of objects are contained in this Log"""
162
+ if len(self) >= 1:
163
+ return isinstance(self[len(self) - 1], obj)
164
+ else:
165
+ return False
166
+
167
+ def display(self):
168
+ """Simple display function to show entire log"""
169
+ for entry in self:
170
+ entry.display()
171
+
172
+ def subset(self, string):
173
+ """Return Log object with subset of entries based on a filter"""
174
+
175
+ newlog = CrunchLog()
176
+ for entry in self:
177
+ if re.search(string, entry.log_entry):
178
+ newlog.append(entry)
179
+
180
+ return newlog
181
+
182
+
183
+ class LogEntry:
184
+ """Interface class which specifies generic log format for consumption
185
+ by other classes"""
186
+ year = ""
187
+ month = ""
188
+ day = ""
189
+ hour = ""
190
+ minute = ""
191
+ second = ""
192
+ host = ""
193
+ daemon = ""
194
+ log_entry = ""
195
+
196
+ def display(self):
197
+ print("Year: ", self.year, \
198
+ "Month:", self.month, \
199
+ "Day:", self.day, \
200
+ "Hour:", self.hour, \
201
+ "Minute:", self.minute, \
202
+ "Second:", self.second, \
203
+ "Host:", self.host, \
204
+ "Payload", self.log_entry)
205
+
206
+ def tally_logic(tally, tally_threshold, max_sample_lines):
207
+ if tally > tally_threshold:
208
+ return True
209
+ else:
210
+ return False
211
+
212
+ # Declare Static Methods
213
+ tally_logic = staticmethod(tally_logic)
214
+
215
+ def set_abnormal(self, value):
216
+ self.year, \
217
+ self.month, \
218
+ self.day, \
219
+ self.hour, \
220
+ self.minute, \
221
+ self.second, \
222
+ self.host, \
223
+ self.daemon = ["1900", "01", "01", "01", "01", "01", "#", "#"]
224
+ self.log_entry = ' '.join(value)
225
+
226
+ def set_blank(self):
227
+ self.year, \
228
+ self.month, \
229
+ self.day, \
230
+ self.hour, \
231
+ self.minute, \
232
+ self.second, \
233
+ self.host, \
234
+ self.daemon = ["1900", "01", "01", "01", "01", "01", "#", "#"]
235
+ self.log_entry = "#"
236
+
237
+
238
+ class SyslogEntry(LogEntry):
239
+ """Driver for Syslog. Conforms to LogEntry interface class."""
240
+
241
+ def __init__(self, line):
242
+
243
+ # Split the line up
244
+ value = line.split()
245
+
246
+ # Should be normal log entry
247
+ if len(value) >= 5:
248
+
249
+ # Syslog does not store year information so, set to current year
250
+ self.year = str(datetime.date.today().year)
251
+ self.month, self.day, clocktime, self.host, self.daemon = value[:5]
252
+ self.log_entry = ' '.join(value[5:])
253
+ self.hour, self.minute, self.second = clocktime.split(":")
254
+
255
+ # Convert month to integer
256
+ self.month = str(time.strptime(self.month, "%b")[1])
257
+
258
+ # Normalize integers to standard widths and convert to strings
259
+ self.year = str("%.4d" % (int(self.year)))
260
+ self.month = str("%.2d" % (int(self.month)))
261
+ self.day = str("%.2d" % (int(self.day)))
262
+ self.hour = str("%.2d" % (int(self.hour)))
263
+ self.minute = str("%.2d" % (int(self.minute)))
264
+ self.second = str("%.2d" % (int(self.second)))
265
+
266
+ # Abnormal log entry
267
+ elif len(value) >= 1:
268
+ self.year, \
269
+ self.month, \
270
+ self.day, \
271
+ self.hour, \
272
+ self.minute, \
273
+ self.second, \
274
+ self.host, \
275
+ self.daemon = ["1900", "01", "01", "01", "01", "01", "#", "#"]
276
+ self.log_entry = ' '.join(value)
277
+
278
+ # Blank line, will be sorted out by scrub
279
+ else:
280
+ self.year, \
281
+ self.month, \
282
+ self.day, \
283
+ self.hour, \
284
+ self.minute, \
285
+ self.second, \
286
+ self.host, \
287
+ self.daemon = ["1900", "01", "01", "01", "01", "01", "#", "#"]
288
+ self.log_entry = "#"
289
+
290
+ def is_type(line):
291
+ """Standard function from interface class to determine type"""
292
+
293
+ global logging
294
+
295
+ if len(line) >= 6:
296
+
297
+ # Look for something similar to: "Feb 29 11:53:08" in first
298
+ # three columns
299
+ if re.search("[A-Z][a-z]{2}", line[0]) and \
300
+ re.search("[0-9][0-9]?", line[1]) and \
301
+ re.search("[0-9{2}:[0-9]{2}:[0-9]{2}", line[2]) and not \
302
+ (re.search("^pam_", line[5]) or \
303
+ re.search(r"^sshd\[", line[4])):
304
+ return True
305
+ else:
306
+ return False
307
+ else:
308
+ return False
309
+
310
+ # Declare Static Methods
311
+ is_type = staticmethod(is_type)
312
+
313
+
314
+ class RSyslogEntry(LogEntry):
315
+ """Driver for RSyslog. Conforms to LogEntry interface class."""
316
+
317
+ def __init__(self, line):
318
+
319
+ # Split the line up
320
+ value = line.split()
321
+
322
+ # Should be normal log entry
323
+ if len(value) >= 5:
324
+
325
+ # Complete major splits: 2010-06-24T17:56:32.197716-04:00
326
+ date, rtime = value[0].split("T") # Raw time
327
+
328
+ # High precision time with timezone info: 17:56:32.197716-04:00
329
+ hptime, offset = rtime.split("-")
330
+
331
+ # Patch for mixed enviornments, milliseconds do not get logged
332
+ # if older Ubuntu 8.04 boxes log to a newer 10.04 server with
333
+ # Rsyslog precision time on.
334
+ if re.search(r"[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{6}", hptime):
335
+ time, mseconds = hptime.split(".") # Miliseconds
336
+ else:
337
+ time = hptime
338
+
339
+ # Complete secondary splits
340
+ self.year, self.month, self.day = date.split("-")
341
+ self.hour, self.minute, self.second = time.split(":")
342
+ self.host = value[1]
343
+ self.daemon = value[2]
344
+ self.log_entry = ' '.join(value[3:])
345
+
346
+ # Normalize integers to standard widths and convert to strings
347
+ self.year = str("%.4d" % (int(self.year)))
348
+ self.month = str("%.2d" % (int(self.month)))
349
+ self.day = str("%.2d" % (int(self.day)))
350
+ self.hour = str("%.2d" % (int(self.hour)))
351
+ self.minute = str("%.2d" % (int(self.minute)))
352
+ self.second = str("%.2d" % (int(self.second)))
353
+
354
+ # Abnormal log entry
355
+ elif len(value) >= 1:
356
+ self.year, \
357
+ self.month, \
358
+ self.day, \
359
+ self.hour, \
360
+ self.minute, \
361
+ self.second, \
362
+ self.host, \
363
+ self.daemon = ["1900", "01", "01", "01", "01", "01", "#", "#"]
364
+ self.log_entry = ' '.join(value)
365
+
366
+ # Blank line, will be sorted out by scrub
367
+ else:
368
+ self.year, \
369
+ self.month, \
370
+ self.day, \
371
+ self.hour, \
372
+ self.minute, \
373
+ self.second, \
374
+ self.host, \
375
+ self.daemon = ["1900", "01", "01", "01", "01", "01", "#", "#"]
376
+ self.log_entry = "#"
377
+
378
+ def is_type(line):
379
+ """Standard function from interface class to determine type"""
380
+
381
+ global logging
382
+
383
+ if len(line) >= 1:
384
+
385
+ # Look for something similar to: "2011-04-04T"
386
+ if re.search("[0-9]{4}-[0-9]{2}-[0-9]{2}T", line[0]):
387
+ return True
388
+ else:
389
+ return False
390
+ else:
391
+ return False
392
+
393
+ # Declare Static Methods
394
+ is_type = staticmethod(is_type)
395
+
396
+
397
+ class ApacheAccessEntry(LogEntry):
398
+ """Driver for Apache Access formatted log files"""
399
+
400
+ def __init__(self, line):
401
+
402
+ # Split the line up
403
+ value = line.split()
404
+
405
+ # Should be normal log entry
406
+ if len(value) >= 12:
407
+ # Grab major chunks from the line
408
+ rhost, \
409
+ ident, \
410
+ ruser, \
411
+ apachedate, \
412
+ junk, \
413
+ junk2, \
414
+ uri, \
415
+ protocol, \
416
+ status, \
417
+ bytes, \
418
+ referer, \
419
+ agent = value[:12]
420
+ self.log_entry = uri
421
+
422
+ # Split up something that looks like this: [03/Aug/2009:11:53:08
423
+ datetime = apachedate.split(':')
424
+ date = datetime[0]
425
+ self.hour = datetime[1]
426
+ self.minute = datetime[2]
427
+ self.second = datetime[3]
428
+ dmy = date.split('/')
429
+ self.day = re.sub(r"\[", "", dmy[0])
430
+ self.month = dmy[1]
431
+ self.year = dmy[2]
432
+ self.host = uri
433
+ daemon = "webserver"
434
+
435
+ # Convert month to integer
436
+ self.month = time.strptime(self.month, "%b")[1]
437
+
438
+ # Normalize integers to standard widths and convert to strings
439
+ self.year = str("%.4d" % (int(self.year)))
440
+ self.month = str("%.2d" % (int(self.month)))
441
+ self.day = str("%.2d" % (int(self.day)))
442
+ self.hour = str("%.2d" % (int(self.hour)))
443
+ self.minute = str("%.2d" % (int(self.minute)))
444
+ self.second = str("%.2d" % (int(self.second)))
445
+
446
+ # Abnormal log entry
447
+ elif len(value) >= 1:
448
+ self.set_abnormal(value)
449
+
450
+ # Blank line, will be sorted out by scrub
451
+ else:
452
+ self.set_blank()
453
+
454
+ def is_type(line):
455
+ """Standard function from interface class to determine type"""
456
+
457
+ global logging
458
+
459
+ if len(line) >= 4:
460
+
461
+ # Look for: "03/Aug/2009:11:53:08" in forth column
462
+ r = "[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:[0-9{2}:[0-9]{2}:[0-9]{2}"
463
+ if re.search(r, line[3]):
464
+ return True
465
+ else:
466
+ return False
467
+ else:
468
+ return False
469
+
470
+ # Declare Static Methods
471
+ is_type = staticmethod(is_type)
472
+
473
+
474
+ class ApacheErrorEntry(LogEntry):
475
+ """Driver for Apache Error formatted log files"""
476
+
477
+ def __init__(self, line):
478
+
479
+ # Split the line up
480
+ value = line.split()
481
+
482
+ # Should be normal log entry
483
+ if len(value) >= 5:
484
+ # Grab major chunks from the line
485
+ # Split up something that looks like this:
486
+ # [Sat Feb 27 12:16:10 2010]
487
+ junk, self.month, self.day, clocktime, self.year = value[:5]
488
+ self.log_entry = ' '.join(value[5:])
489
+ self.hour, self.minute, self.second = clocktime.split(":")
490
+
491
+ # Convert month to integer
492
+ self.month = time.strptime(self.month, "%b")[1]
493
+
494
+ # Clean up the year field
495
+ self.year = re.sub(r"\]", "", self.year)
496
+
497
+ # Normalize integers to standard widths and convert to strings
498
+ self.year = str("%.4d" % (int(self.year)))
499
+ self.month = str("%.2d" % (int(self.month)))
500
+ self.day = str("%.2d" % (int(self.day)))
501
+ self.hour = str("%.2d" % (int(self.hour)))
502
+ self.minute = str("%.2d" % (int(self.minute)))
503
+ self.second = str("%.2d" % (int(self.second)))
504
+
505
+ # Abnormal log entry
506
+ elif len(value) >= 1:
507
+ self.set_abnormal(value)
508
+
509
+ # Blank line, will be sorted out by scrub
510
+ else:
511
+ self.set_blank()
512
+
513
+ def is_type(line):
514
+ """Standard function from interface class to determine type"""
515
+
516
+ global logging
517
+
518
+ if len(line) >= 5:
519
+
520
+ # Look for : [Sat Feb 27 12:16:10 2010]
521
+ if re.search(r"[\[a-zA-Z]{3}", line[0]) and \
522
+ re.search("[0-9]{2}:[0-9]{2}:[0-9]{2}", line[3]) and \
523
+ re.search("[0-9]{4}", line[4]):
524
+ return True
525
+ else:
526
+ return False
527
+ else:
528
+ return False
529
+
530
+ # Declare Static Methods
531
+ is_type = staticmethod(is_type)
532
+
533
+
534
+ class SecureLogEntry(LogEntry):
535
+ """Driver for Syslog. Conforms to LogEntry interface class."""
536
+
537
+ def __init__(self, line):
538
+
539
+ # Split the line up
540
+ value = line.split()
541
+
542
+ # Should be normal log entry
543
+ if len(value) >= 5:
544
+ # Syslog does not store year information so, set to current year
545
+ self.year = str(datetime.date.today().year)
546
+ self.month, self.day, clocktime, self.host, self.daemon = value[:5]
547
+ self.log_entry = ' '.join(value[5:])
548
+ self.hour, self.minute, self.second = clocktime.split(":")
549
+
550
+ # Convert month to integer
551
+ self.month = str(time.strptime(self.month, "%b")[1])
552
+
553
+ # Normalize integers to standard widths
554
+ self.year = str("%.4d" % (int(self.year)))
555
+ self.month = str("%.2d" % (int(self.month)))
556
+ self.day = str("%.2d" % (int(self.day)))
557
+ self.hour = str("%.2d" % (int(self.hour)))
558
+ self.minute = str("%.2d" % (int(self.minute)))
559
+ self.second = str("%.2d" % (int(self.second)))
560
+
561
+ # Abnormal log entry
562
+ elif len(value) >= 1:
563
+ self.set_abnormal(value)
564
+
565
+ # Blank line, will be sorted out by scrub
566
+ else:
567
+ self.set_blank()
568
+
569
+ def is_type(line):
570
+ """Standard function from interface class to determine type"""
571
+
572
+ global logging
573
+
574
+ if len(line) >= 6:
575
+
576
+ # Look for something similar to: "29 11:53:08" in third column
577
+ if re.search("[0-9][0-9]?", line[1]) \
578
+ and re.search("[0-9{2}:[0-9]{2}:[0-9]{2}", line[2]) \
579
+ and (re.search("^pam_", line[5]) \
580
+ or re.search(r"^sshd\[", line[4])):
581
+ return True
582
+ else:
583
+ return False
584
+ else:
585
+ return False
586
+
587
+ # Declare Static Methods
588
+ is_type = staticmethod(is_type)
589
+
590
+ def tally_logic(tally, tally_threshold, max_sample_lines):
591
+ """Override tally logic for secure logs"""
592
+
593
+ if tally >= max_sample_lines:
594
+ return True
595
+ else:
596
+ return False
597
+
598
+ # Declare Static Methods
599
+ tally_logic = staticmethod(tally_logic)
600
+
601
+
602
+ class ScriptlogEntry(LogEntry):
603
+ """
604
+ Driver for scriptlog entries. Conforms to LogEntry interface class.
605
+ This allows for a standard syslog entry to have extra fields which
606
+ are used with scriptlogs.
607
+ """
608
+
609
+ # Extra variables
610
+ label = "__none__"
611
+ id = "__none__"
612
+ type = "__none__"
613
+
614
+ def __init__(self, line):
615
+
616
+ # Split the line up
617
+ value = line.split()
618
+
619
+ # Should be normal log entry
620
+ if len(value) >= 5:
621
+
622
+ # Syslog does not store year information so scriptlog does not
623
+ # So set to current year, set the other fields normally
624
+ self.year = datetime.date.today().year
625
+ self.month, \
626
+ self.day, \
627
+ time, \
628
+ self.host, \
629
+ self.daemon, \
630
+ self.label, \
631
+ self.id, \
632
+ self.type = value[:8]
633
+
634
+ self.log_entry = ' '.join(value[8:])
635
+ self.hour, self.minute, self.second = time.split(":")
636
+
637
+ # Normalize integers to standard widths and convert to strings
638
+ self.year = str("%.4d" % (int(self.year)))
639
+ self.month = str("%.2d" % (int(self.month)))
640
+ self.day = str("%.2d" % (int(self.day)))
641
+ self.hour = str("%.2d" % (int(self.hour)))
642
+ self.minute = str("%.2d" % (int(self.minute)))
643
+ self.second = str("%.2d" % (int(self.second)))
644
+
645
+ # Abnormal log entry
646
+ elif len(value) >= 1:
647
+ self.set_abnormal(value)
648
+
649
+ # Blank line, will be sorted out by scrub
650
+ else:
651
+ self.set_blank()
652
+
653
+ def is_type(line, label="__none__"):
654
+ """Standard function from interface class to determine type"""
655
+
656
+ # Split the line up
657
+ value = str(line).split()
658
+
659
+ if len(value) >= 8:
660
+
661
+ # Look for special label to determine scriptlog type
662
+ if re.search(re.escape(value[5]), re.escape(label)):
663
+ return True
664
+ else:
665
+ return False
666
+ else:
667
+ return False
668
+
669
+ # Declare Static Methods
670
+ is_type = staticmethod(is_type)
671
+
672
+
673
+ class RawEntry(LogEntry):
674
+ """
675
+ Driver for Raw log files. Conforms to LogEntry interface class.
676
+ This also allows raw logs to contain all of the correct fields
677
+ to be worked with just like other entries that actually have time
678
+ values
679
+ """
680
+
681
+ def __init__(self, line):
682
+
683
+ # Split the line up
684
+ value = line.split()
685
+
686
+ # Fake the time/date values, put the entire line in the key
687
+ if len(value) >= 1:
688
+ self.set_abnormal(value)
689
+
690
+ # Blank line, will be sorted out by scrub
691
+ else:
692
+ self.set_blank()
693
+
694
+ def is_type(line):
695
+ """
696
+ Do minimum checking to ensure there is some data
697
+ """
698
+
699
+ if len(line) >= 1:
700
+
701
+ # Look for any length of text in the line
702
+ if re.search(".+", str(line)):
703
+ return True
704
+ else:
705
+ return False
706
+ else:
707
+ return False
708
+
709
+ # Declare Static Methods
710
+ is_type = staticmethod(is_type)
711
+
712
+
713
+ class SnortEntry(LogEntry):
714
+ """
715
+ Driver for Snort formatted log files. Conforms to LogEntry interface class.
716
+ """
717
+
718
+ def __init__(self, line):
719
+
720
+ # Split the line up
721
+ value = line.split()
722
+
723
+ # Should be normal log entry
724
+ if len(value) >= 2:
725
+
726
+ # Snort does not store year information so, set to current year
727
+ self.year = datetime.date.today().year
728
+
729
+ # Initial break down
730
+ snortdate = value[:1]
731
+ self.log_entry = ' '.join(value[1:])
732
+
733
+ # Looks like "09/29-10:18:46.026172"
734
+ snortdate, junk = snortdate[0].split('.')
735
+
736
+ # Looks like "09/29-10:18:46"
737
+ self.month, snortdate = snortdate.split('/')
738
+
739
+ # Looks like "29-10:18:46"
740
+ self.day, snortdate = snortdate.split('-')
741
+
742
+ # Looks like "10:18:46"
743
+ self.hour, self.minute, self.second = snortdate.split(':')
744
+
745
+ # Normalize integers to standard widths and convert to strings
746
+ self.year = str("%.4d" % (int(self.year)))
747
+ self.month = str("%.2d" % (int(self.month)))
748
+ self.day = str("%.2d" % (int(self.day)))
749
+ self.hour = str("%.2d" % (int(self.hour)))
750
+ self.minute = str("%.2d" % (int(self.minute)))
751
+ self.second = str("%.2d" % (int(self.second)))
752
+
753
+ # Abnormal value
754
+ elif len(value) >= 1:
755
+ self.set_abnormal(value)
756
+
757
+ # Blank line, will be sorted out by scrub
758
+ else:
759
+ self.set_blank()
760
+
761
+ def is_type(line):
762
+
763
+ global logging
764
+
765
+ if len(line) >= 4:
766
+
767
+ # Look for : "09/29-10:18:46.026172" in first column
768
+ r = r"[0-9]{2}\/[0-9]{2}\-[0-9]{2}\:[0-9]{2}\:[0-9]{2}\.[0-9]{6}"
769
+ if re.search(r, line[0]):
770
+ return True
771
+ else:
772
+ return False
773
+ else:
774
+ return False
775
+
776
+ # Declare Static Methods
777
+ is_type = staticmethod(is_type)
778
+
779
+
780
+ # Automatically load a list of drivers for each file type this will be used
781
+ # to determine what kind of log it is. Do NOT append the parent LogEntry and
782
+ # append RawEntry to the end to preserve last resort logic
783
+ ma = sys.modules[__name__].__dict__ # module attributes
784
+ entry_types = list()
785
+
786
+ for i in list(ma.keys()):
787
+ if isinstance(ma[i], type):
788
+ if issubclass(ma[i], ma['LogEntry']) and \
789
+ ma[i].__name__ != "LogEntry" and \
790
+ ma[i].__name__ != "RawEntry":
791
+ entry_types.append(ma[i])
792
+
793
+ entry_types.append(RawEntry)