The Assimilation Project  based on Assimilation version 1.1.7.1474836767
checksumdiscovery.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # vim: smartindent tabstop=4 shiftwidth=4 expandtab number colorcolumn=80
3 #
4 # This file is part of the Assimilation Project.
5 #
6 # Author: Alan Robertson <alanr@unix.sh>
7 # Copyright (C) 2013-2015 - Assimilation Systems Limited
8 #
9 # Free support is available from the Assimilation Project community
10 # - http://assimproj.org
11 # Paid support is available from Assimilation Systems Limited
12 # - http://assimilationsystems.com
13 #
14 # The Assimilation software is free software: you can redistribute it and/or
15 # modify # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
18 #
19 # The Assimilation software is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with the Assimilation Project software.
26 # If not, see http://www.gnu.org/licenses/
27 #
28 #
29 
30 '''
31 Checksum generation/checking code.
32 This is the class which wants to perform checksums and also
33 wants to hear about checksums as they are computed.
34 
35 It's interesting that we ask for a certain set of files to be checksummed
36 but the discovery agent actually checksums those files and the ones that
37 ldd says those files use. So we typically wind up checksumming more files
38 than we asked for.
39 
40 If we ask for a file which doesn't exist (like bad JARs in the CLASSPATH),
41 then those files won't show up in the results.
42 '''
43 import sys
44 from systemnode import SystemNode
45 from AssimCclasses import pyConfigContext
46 from AssimCtypes import CONFIGNAME_TYPE, CONFIGNAME_INSTANCE
47 from assimevent import AssimEvent
48 from cmaconfig import ConfigFile
49 
50 from discoverylistener import DiscoveryListener
51 
52 @SystemNode.add_json_processor
53 class TCPDiscoveryChecksumGenerator(DiscoveryListener):
54  'Class for generating checksums based on our tcpdiscovery packets'
55  prio = DiscoveryListener.PRI_OPTION
56  wantedpackets = ('tcpdiscovery', 'checksum')
57 
58  def processpkt(self, drone, srcaddr, jsonobj, discoverychanged):
59  '''Inform interested rule objects about this change'''
60  if not discoverychanged:
61  return
62  if jsonobj['discovertype'] == 'tcpdiscovery':
63  self.processtcpdiscoverypkt(drone, srcaddr, jsonobj)
64  elif jsonobj['discovertype'] == 'checksum':
65  self.processchecksumpkt(drone, srcaddr, jsonobj)
66  else:
67  print >> sys.stderr, ('OOPS! bad packet type [%s]' %
68  jsonobj['discovertype'])
69 
70  def processtcpdiscoverypkt(self, drone, unused_srcaddr, jsonobj):
71  "Send commands generating checksums for the Systems's net-facing things"
72  unused_srcaddr = unused_srcaddr
73  params = ConfigFile.agent_params(self.config, 'discovery', 'checksums',
74  drone.designation)
75  sumcmds = self.config['checksum_cmds']
76  filelist = self.config['checksum_files']
77  filelist.extend(sumcmds)
78  params['parameters'] = pyConfigContext()
79  params[CONFIGNAME_TYPE] = 'checksums'
80  params[CONFIGNAME_INSTANCE] = '_auto_checksumdiscovery'
81  data = jsonobj['data'] # The data portion of the JSON message
82  for procname in data.keys(): # List of of process names...
83  procinfo = data[procname] # (names assigned by the nanoprobe)
84  if 'exe' not in procinfo:
85  continue
86  exename = procinfo.get('exe')
87  # dups (if any) are removed by the agent
88  filelist.append(exename)
89  if exename.endswith('/java'):
90  # Special case for some/many JAVA programs - find the jars...
91  if 'cmdline' not in procinfo:
92  continue
93  cmdline = procinfo.get('cmdline')
94  for j in range(0, len(cmdline)):
95  # The argument following -cp is the ':'-separated CLASSPATH
96  if cmdline[j] == '-cp' and j < len(cmdline)-1:
97  jars = cmdline[j+1].split(':')
98  for jar in jars:
99  filelist.append(jar)
100  break
101 
102  params['parameters']['ASSIM_sumcmds'] = sumcmds
103  params['parameters']['ASSIM_filelist'] = filelist
104  # Request checksums of all the binaries talking (tcp) over the network
105  print >> sys.stderr, ('REQUESTING CHECKSUM MONITORING OF %d files'
106  % (len(params['parameters']['ASSIM_filelist'])))
107  drone.request_discovery((params,))
108 
109  def processchecksumpkt(self, drone, unused_srcaddr, jsonobj):
110  '''Process updated checksums. Note that our drone-owned-JSON is already
111  updated. This is a mistake. We should update attributes at the end
112  of a transaction. I wonder if this is in fact the case with the new
113  storage method for JSON string attributes.
114  '''
115  unused_srcaddr = unused_srcaddr # make pylint happy...
116  data = jsonobj['data'] # The data portion of the JSON message
117  print >> sys.stderr, 'PROCESSING CHECKSUM DATA'
118  if ('OLD_checksums' in drone):
119  print >> sys.stderr, 'COMPARING CHECKSUM DATA'
120  olddata = pyConfigContext(drone['OLD_checksums'])['data']
121  self.compare_checksums(drone, olddata, data)
122  print >> sys.stderr, 'UPDATING CHECKSUM DATA for %d files' % len(data)
123  drone['OLD_checksums'] = str(jsonobj)
124 
125  def compare_checksums(self, drone, oldobj, newobj):
126  'Compare checksums and complain about those that change'
127  designation = drone.designation
128  changes = {}
129  for oldfile in oldobj.keys():
130  if oldfile not in newobj:
131  continue
132  oldchecksum = oldobj[oldfile]
133  newchecksum = newobj[oldfile]
134  if oldchecksum == newchecksum:
135  continue
136  self.log.warning('On system %s: %s had checksum %s which is now %s'
137  % (designation, oldfile, oldchecksum, newchecksum))
138  changes[oldfile] = (oldchecksum, newchecksum)
139  extrainfo = {'CHANGETYPE': 'checksums', 'changes': changes}
140  AssimEvent(drone, AssimEvent.OBJUPDATE, extrainfo=extrainfo)
def processtcpdiscoverypkt(self, drone, unused_srcaddr, jsonobj)
def processchecksumpkt(self, drone, unused_srcaddr, jsonobj)
def processpkt(self, drone, srcaddr, jsonobj, discoverychanged)
def compare_checksums(self, drone, oldobj, newobj)