The unified diff between revisions [9f83aa07..] and [ba381432..] is displayed below. It can also be downloaded as a raw diff.
#
#
# delete "client/iptables.py"
#
# delete "client/opensshconfig.py"
#
# add_dir "client/plugins"
#
# add_dir "service"
#
# add_file "client/plugins/debiansecurity.py"
# content [774a316e541ba81ae0f8d1ea962bdb38644ea53f]
#
# add_file "client/plugins/iptables.py"
# content [1b153de261ff6843afbed6103461f9fdb4e7c9d8]
#
# add_file "client/plugins/opensshconfig.py"
# content [4b5714b6385033d91c719070eb9b775564fc2d64]
#
# add_file "service/service.py"
# content [37a31e887b320de737da756b4809c9228df4deec]
#
============================================================
--- client/plugins/debiansecurity.py 774a316e541ba81ae0f8d1ea962bdb38644ea53f
+++ client/plugins/debiansecurity.py 774a316e541ba81ae0f8d1ea962bdb38644ea53f
@@ -0,0 +1,76 @@
+
+#
+# this plugin will check whether the machine requires any urgent security
+# updates
+#
+
+import StringIO
+import apt_listchanges
+import apt_pkg
+import urllib
+import pipes
+import rfc822
+import glob
+import sys
+import os
+import re
+
+apt_get = '/usr/bin/apt-get '
+apt_cache = '/usr/bin/apt-cache '
+cache = '/var/cache/apt/archives/'
+
+urgency_str = { 1 : 'low', 2 : 'medium', 3 : 'high', 4 : 'critical' }
+
+def run():
+ results = []
+
+ config = apt_listchanges.Config()
+ config.read('/etc/apt/listchanges.conf')
+ apt_pkg.InitSystem()
+
+ def run_silently(command):
+ fd = os.popen(command)
+ fd.read()
+ fd.close()
+
+ # update apt packages lists
+ #run_silently(apt_get + 'update')
+ # download the packages
+ run_silently(apt_get + 'dist-upgrade -d -y')
+
+ packages = []
+ r = re.compile(r'^Inst ([a-z0-9\+\-\.]+) \[([A-Za-z0-9\.\+\-\:]+)\] \(([A-Za-z0-9\.\+\-\:]+) (.*)\)')
+ for line in os.popen(apt_get + 'dist-upgrade -s -y'):
+ m = r.match(line)
+ if m: packages.append(m.groups())
+
+ for package_name, installed_version, new_version, source in packages:
+ filename = package_name + '_' + new_version
+ # unfortunately we can't use urllib.quote() as its behaviour differs
+ # from whatever apt does.
+ filename = filename.replace(':', '%3a')
+ g = os.path.join(cache, filename + "*.deb")
+ matches = glob.glob(g)
+ if len(matches) == 0:
+ results.append(('low', 'No matches for glob %s' % (g)))
+ continue
+ elif len(matches) > 1:
+ results.append(('low', 'More than one match for glob %s' % (g)))
+ continue
+ filename = matches[0]
+
+ pkg = apt_listchanges.Package(filename)
+ (news, changelog) = pkg.extract_changes(config.which, installed_version)
+ if changelog == None:
+ # probably not a problem; some packages just don't have Changelogs, but
+ # if it's a security upload they will do..
+ # results.append(('low', 'unable to get changelog from package: ' + filename))
+ continue
+ if changelog.changes.lower().find('security') != -1:
+ security = ' (security)'
+ else:
+ security = ''
+ results.append ((urgency_str.get(changelog.urgency, str(changelog.urgency)),
+ package_name + security))
+
+ return results
============================================================
--- client/plugins/iptables.py 1b153de261ff6843afbed6103461f9fdb4e7c9d8
+++ client/plugins/iptables.py 1b153de261ff6843afbed6103461f9fdb4e7c9d8
@@ -0,0 +1,16 @@
+
+import os
+
+def run():
+ # for now, just check that there are rules
+ iptables_command = '/sbin/iptables -L INPUT -n'
+
+ fd = os.popen(iptables_command)
+ result = fd.read()
+ fd.close()
+
+ line_count = len(result.split('\n'))
+ if line_count > 3:
+ return []
+ else:
+ return [("medium", 'no iptables rules in chain "INPUT"')]
============================================================
--- client/plugins/opensshconfig.py 4b5714b6385033d91c719070eb9b775564fc2d64
+++ client/plugins/opensshconfig.py 4b5714b6385033d91c719070eb9b775564fc2d64
@@ -0,0 +1,14 @@
+
+def run():
+ results = []
+ sshd_config_file = '/etc/ssh/sshd_config'
+ for line in open(sshd_config_file):
+ line = line.strip().lower()
+ fields = [t for t in line.split(' ') if t]
+ if len(fields) != 2:
+ continue
+ key, value = fields
+ if key == 'permitrootlogin':
+ if value == 'yes':
+ results.append(("high", "Root may log in using a password."))
+ return results
============================================================
--- service/service.py 37a31e887b320de737da756b4809c9228df4deec
+++ service/service.py 37a31e887b320de737da756b4809c9228df4deec
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+
+import os
+import sys
+import service
+import syslog
+import traceback
+from ZSI import dispatch
+from mod_python import apache
+import libpq
+import config
+
+mod = __import__('encodings.utf_8', globals(), locals(), '*')
+mod = __import__('encodings.utf_16_be', globals(), locals(), '*')
+
+class ServiceMethods:
+ def __init__(self, req):
+ self.req = req
+ self.cnx = libpq.PQconnectdb(config.sql_connect_string)
+ def plugin_results(self, results):
+ # results is a list of (plugin,urgency,description)
+ q = libpq.PgQuoteString
+ remote_host = req.get_remote_host(apache.REMOTE_NOLOOKUP)
+ for plugin, urgency, description in results:
+ query = 'INSERT INTO plugin_results (ip_address, plugin, urgency, description) VALUES (%s,%s,%s,%s)' % \
+ (q(remote_host), q(plugin), q(urgency), q(description))
+ self.cnx.query(query)
+ return True
+
+def handler(req):
+ methods = ServiceMethods(req)
+ dispatch.AsHandler(modules=(methods,), request=req)
+ return apache.OK
+
+def authenhandler(req):
+ passphrase_file = '/home/grahame/monotone/phonehome/passphrases'
+ passphrases = {}
+ for line in open(passphrase_file):
+ line = line.strip()
+ if not line: continue
+ fields = line.split()
+ passphrases[fields[0]] = fields[1]
+
+ remote_host = req.get_remote_host(apache.REMOTE_NOLOOKUP)
+ pw = req.get_basic_auth_pw()
+ if not passphrases.has_key(remote_host):
+ return apache.HTTP_UNAUTHORIZED
+ if pw == passphrases[remote_host]:
+ return apache.OK
+ else:
+ return apache.HTTP_UNAUTHORIZED
+