granitepenguin icon

RH Satellite vulnerability report

granitepenguin | PRO | 03/13/13 03:35:09 PM UTC | 0 ⭐ | 384 👁️ | Never ⏰ | []
Python |

16.61 KB

|

None

|

0 👍

/

0 👎

#!/usr/bin/env python
# vim:ts=4 sw=4 et:
#
# vulnerability_report.py
#
# dumps a vulnerability report, but will also do it based on full errata, not just what
# is available in the clone channel a system is tied to.
# This does assume satellite >= 5.4.0.  I have no idea if 5.3 will work yet.
 
import sys
import xmlrpclib
import pprint
import ConfigParser
from optparse import OptionParser
 
def getArch(arch):
    '''
        This is a function because the API doesn't return good data.
        Specifically system.listPackages() returns AMD64 for the arch instead
        of x86_64.  If you try to use the arch value directly in packages.findByNvrea()
        it will blow up in your face.
    '''
    if arch == 'AMD64':
        return 'x86_64'
    else:
        return arch
 
parser = OptionParser()
parser.add_option("-c", "--configfile", action="store", type="string",
                    dest="configfile", help="Alternate config file to set defaults")
parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Turn on Debug mode")
parser.add_option("-l", "--login", dest="login", help="Satellite Server Login Name")
parser.add_option("-p", "--password", dest="password", help="Satellite Server Password")
parser.add_option("-u", "--url", dest="url", help="URL of Satellite Server")
parser.set_defaults(configfile=False)
parser.set_defaults(debug=False)
parser.set_defaults(url='http://localhost/rpc/api')
(options, args) = parser.parse_args()
 
 
if __name__ == '__main__':
 
    login = False
    password = False
 
    # Read config file for options
    if options.configfile:
        config = ConfigParser.ConfigParser()
        config.read(options.configfile)
        try:
            url = config.get('config','url')
        except ConfigParser.NoOptionError:
            pass
        except ConfigParser.NoSectionError:
            parser.print_help()
            print
            print >>sys.stderr, 'No config section found in your config file.'
            print >>sys.stderr, 'Please verify that %s exists and has the correct syntax.' % (options.configfile)
            sys.exit(1)
        try:
            login = config.get('config','login')
        except ConfigParser.NoOptionError:
            pass
        try:
            password = config.get('config','password')
        except ConfigParser.NoOptionError:
            pass
 
    url = options.url
    debug = options.debug
    if options.login:
        login = options.login
    if options.password:
        password = options.password
 
    # Various checks up front to save time
    if login and password:
        client = xmlrpclib.Server(url, verbose=0)
        authKey = client.auth.login(login, password)
    else:
        parser.print_help()
        parser.error("Login or Password have not been defined on the commandline or in a config file")
 
    # Establish which system arch types to look for
    rhel5_x64 = False
    rhel4_x64 = False
    rhel3_x64 = False
    rhel5_i386 = False
    rhel4_i386 = False
    rhel3_i386 = False
 
    # get a list of servers to iterate over
    if debug:
        print >>sys.stderr, "Starting collection of system names"
    active_systems = []
    if args:
        args.sort()
        for system in args:
            try:
                data = client.system.getId(authKey,system)[0]
                cpu = client.system.getCpu(authKey,data['id'])
                detail = client.system.getDetails(authKey,data['id'])
                if cpu['arch'] == 'x86_64':
                    if detail['release'] == '5Server':
                        rhel5_x64 = True
                    if detail['release'] == '4AS':
                        rhel4_x64 = True
                    if detail['release'] == '3AS':
                        rhel3_x64 = True
                if cpu['arch'] == 'i386' or cpu['arch'] == 'i686':
                    if detail['release'] == '5Server':
                        rhel5_i386 = True
                    if detail['release'] == '4AS':
                        rhel4_i386 = True
                    if detail['release'] == '3AS':
                        rhel3_i386 = True
                data['arch'] = cpu['arch']
                data['release'] = detail['release']
                active_systems.append(data)
            except:
                print >>sys.stderr, "ERROR: Could not identify servername: %s" % system
    else:
        systems = sorted(client.system.listActiveSystems(authKey), key=lambda k: k['name'])
        for system in systems:
            data = system
            cpu = client.system.getCpu(authKey,data['id'])
            detail = client.system.getDetails(authKey,data['id'])
            data['arch'] = cpu['arch']
            data['release'] = detail['release']
            active_systems.append(data)
        rhel5_x64 = True
        rhel4_x64 = True
        rhel3_x64 = True
        rhel5_i386 = True
        rhel4_i386 = True
        rhel3_i386 = True
 
    # ALL RHEL3-64 Packages
    if rhel3_x64:
        if debug:
            print >>sys.stderr, "Starting collection of RHEL3 64bit"
        rhel3 = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-3')
        rhel3_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-3-as-x86_64')
        rhel3_x64_all = rhel3 + rhel3_tools
 
    # ALL RHEL3-32 Packages
    if rhel3_i386:
        if debug:
            print >>sys.stderr, "Starting collection of RHEL3 32bit"
        rhel3 = client.channel.software.listAllPackages(authKey,'rhel-i386-as-3')
        rhel3_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-3-as-i386')
        rhel3_i386_all = rhel3 + rhel3_tools
 
    # ALL RHEL4-64 Packages
    if rhel4_x64:
        if debug:
            print >>sys.stderr, "Starting collection of RHEL4 64bit"
        rhel4 = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4')
        rhel4_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-4-as-x86_64')
        rhel4_cluster = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4-cluster')
        rhel4_gfs = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4-gfs-6.1')
        rhel4_proxy = client.channel.software.listAllPackages(authKey,'redhat-rhn-proxy-5.1-as-x86_64-4')
        rhel4_extras = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4-extras')
        rhel4_x64_all = rhel4 + rhel4_tools + rhel4_cluster + rhel4_gfs + rhel4_proxy + rhel4_extras
 
    # ALL RHEL4-32 Packages
    if rhel4_i386:
        if debug:
            print >>sys.stderr, "Starting collection of RHEL4 32bit"
        rhel4 = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4')
        rhel4_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-4-as-i386')
        rhel4_cluster = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4-cluster')
        rhel4_gfs = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4-gfs-6.1')
        rhel4_proxy = client.channel.software.listAllPackages(authKey,'redhat-rhn-proxy-5.1-as-i386-4')
        rhel4_extras = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4-extras')
        rhel4_i386_all = rhel4 + rhel4_tools + rhel4_cluster + rhel4_gfs + rhel4_proxy + rhel4_extras
 
    # ALL RHEL5-64 Packages
    if rhel5_x64:
        if debug:
            print >>sys.stderr, "Starting collection of RHEL5 64bit"
        rhel5 = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-5')
        rhel5_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-x86_64-server-5')
        rhel5_cluster_storage = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-cluster-storage-5')
        rhel5_cluster = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-cluster-5')
        rhel5_prod = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-productivity-5')
        rhel5_supp = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-supplementary-5')
        rhel5_virt = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-vt-5')
        rhel5_x64_all = rhel5 + rhel5_tools + rhel5_cluster_storage + rhel5_cluster + rhel5_prod + rhel5_supp + rhel5_virt
 
    # ALL RHEL5-32 Packages
    if rhel5_i386:
        if debug:
            print >>sys.stderr, "Starting collection of RHEL5 32bit"
        rhel5 = client.channel.software.listAllPackages(authKey,'rhel-i386-server-5')
        rhel5_proxy = client.channel.software.listAllPackages(authKey,'redhat-rhn-proxy-5.3-server-i386-5')
        rhel5_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-i386-server-5')
        rhel5_cluster_storage = client.channel.software.listAllPackages(authKey,'rhel-i386-server-cluster-storage-5')
        rhel5_cluster = client.channel.software.listAllPackages(authKey,'rhel-i386-server-cluster-5')
        rhel5_prod = client.channel.software.listAllPackages(authKey,'rhel-i386-server-productivity-5')
        rhel5_supp = client.channel.software.listAllPackages(authKey,'rhel-i386-server-supplementary-5')
        rhel5_i386_all = rhel5 + rhel5_proxy + rhel5_tools + rhel5_cluster_storage + rhel5_cluster + rhel5_prod + rhel5_supp
 
    for system in active_systems:
        # re-auth every system to avoid timeouts
        authKey = client.auth.login(login, password)
        system_package_list = client.system.listPackages(authKey,system['id'])
        package_dict = {}
        unmatched_packages = []
        try:
            if system['arch'] == 'x86_64':
                if system['release'] == '5Server':
                    if debug:
                        print >>sys.stderr, "RHEL5 64bit collected"
                    base_package_list = rhel5_x64_all
                elif system['release'] == '4AS':
                    if debug:
                        print >>sys.stderr, "RHEL4 64bit collected"
                    base_package_list = rhel4_x64_all
                else:
                    if debug:
                        print >>sys.stderr, "RHEL3 64bit collected"
                    base_package_list = rhel3_x64_all
            if system['arch'] == 'i386' or system['arch'] == 'i686':
                if system['release'] == '5Server':
                    if debug:
                        print >>sys.stderr, "RHEL5 32bit collected"
                    base_package_list = rhel5_i386_all
                elif system['release'] == '4AS':
                    if debug:
                        print >>sys.stderr, "RHEL4 32bit collected"
                    base_package_list = rhel4_i386_all
                else:
                    if debug:
                        print >>sys.stderr, "RHEL3 32bit collected"
                    base_package_list = rhel3_i386_all
        except:
            base_package_list = []
            print 'WARNING, Unable to find packages -- System: %s, Arch: %s, Release: %s' % (system['name'],
                                                                                            system['arch'],
                                                                                            system['release'],)
            continue
 
        for package in system_package_list:
            arch = getArch(package['arch'])
            matched = False
            for base_package in base_package_list:
                pname = package['name'] == base_package['name']
                parch = arch == base_package['arch_label']
                release = package['release'] == base_package['release']
                version = package['version'] == base_package['version']
                if pname:
                    matched = True
                    pkey = base_package['name']+base_package['arch_label']
                    package_dict.setdefault(pkey,{})
                    package_dict[pkey][base_package['id']] = {}
                    package_dict[pkey][base_package['id']]['data'] = base_package
                    if release and version:
                        package_dict[pkey][base_package['id']]['current'] = True
                    else:
                        package_dict[pkey][base_package['id']]['current'] = False
            if not matched:
                unmatched_packages.append(package['name']+'.'+package['arch'])
 
        bugfix_list = {}
        security_list = {}
        enhancement_list = {}
 
        package_keys = package_dict.keys()
        package_keys.sort()
        for package in package_keys:
            get_advisory = False
            current = 0
            pkg = package_dict[package]
            pkg_keys = pkg.keys()
            pkg_keys.sort()
            for pkey in pkg_keys:
                if pkg[pkey]['current']:
                    if not pkey == pkg_keys[-1]:
                        get_advisory = True
                        current = pkg[pkey]['data']['id']
                    continue
                if get_advisory:
                    advisories = client.packages.listProvidingErrata(authKey,pkg[pkey]['data']['id'])
                    for advisory in advisories:
                        if 'RH' in advisory['advisory']:
                            if 'Bug Fix Advisory' in advisory['type']:
                                try:
                                    bugfix_list[advisory['advisory']].append(pkg[pkey]['data'])
                                except:
                                    bugfix_list[advisory['advisory']] = []
                                    bugfix_list[advisory['advisory']].append(pkg[pkey]['data'])
                            if 'Security Advisory' in advisory['type']:
                                try:
                                    security_list[advisory['advisory']].append(pkg[pkey]['data'])
                                except:
                                    security_list[advisory['advisory']] = []
                                    security_list[advisory['advisory']].append(pkg[pkey]['data'])
                            if 'Product Enhancement Advisory' in advisory['type']:
                                try:
                                    enhancement_list[advisory['advisory']].append(pkg[pkey]['data'])
                                except:
                                    enhancement_list[advisory['advisory']] = []
                                    enhancement_list[advisory['advisory']].append(pkg[pkey]['data'])
                            #print 'ADVISORY ALERT %s:%s -- Package: %s %s %s, Base Package: %s %s %s' % (advisory['advisory'],
                            #                                                                            advisory['type'],
                            #                                                                            pkg[current]['data']['name'],
                            #                                                                            pkg[current]['data']['version'],
                            #                                                                            pkg[current]['data']['release'],
                            #                                                                            pkg[pkey]['data']['name'],
                            #                                                                            pkg[pkey]['data']['version'],
                            #                                                                            pkg[pkey]['data']['release'])
 
        print 'System: %s, Arch: %s, Release: %s, Bugfixes: %d, Security Fixes: %d, Enhancements: %d' % (system['name'],
                                                                                                system['arch'],
                                                                                                system['release'],
                                                                                                len(bugfix_list),
                                                                                                len(security_list),
                                                                                                len(enhancement_list))
        if debug:
            print
            print 'UNMATCHED PACKAGES'
            pprint.pprint(unmatched_packages)
            print
            print 'BUGFIX LIST'
            pprint.pprint(bugfix_list)
            print
            print 'SECURITY LIST'
            pprint.pprint(security_list)
            print
            print 'ENHANCEMENT LIST'
            pprint.pprint(enhancement_list)
        sys.stdout.flush()
 
    client.auth.logout(authKey)

Comments