granitepenguin

RH Satellite vulnerability report

Mar 13th, 2013
414
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.61 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # vim:ts=4 sw=4 et:
  3. #
  4. # vulnerability_report.py
  5. #
  6. # dumps a vulnerability report, but will also do it based on full errata, not just what
  7. # is available in the clone channel a system is tied to.
  8. # This does assume satellite >= 5.4.0.  I have no idea if 5.3 will work yet.
  9.  
  10. import sys
  11. import xmlrpclib
  12. import pprint
  13. import ConfigParser
  14. from optparse import OptionParser
  15.  
  16. def getArch(arch):
  17.     '''
  18.        This is a function because the API doesn't return good data.
  19.        Specifically system.listPackages() returns AMD64 for the arch instead
  20.        of x86_64.  If you try to use the arch value directly in packages.findByNvrea()
  21.        it will blow up in your face.
  22.    '''
  23.     if arch == 'AMD64':
  24.         return 'x86_64'
  25.     else:
  26.         return arch
  27.  
  28. parser = OptionParser()
  29. parser.add_option("-c", "--configfile", action="store", type="string",
  30.                     dest="configfile", help="Alternate config file to set defaults")
  31. parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Turn on Debug mode")
  32. parser.add_option("-l", "--login", dest="login", help="Satellite Server Login Name")
  33. parser.add_option("-p", "--password", dest="password", help="Satellite Server Password")
  34. parser.add_option("-u", "--url", dest="url", help="URL of Satellite Server")
  35. parser.set_defaults(configfile=False)
  36. parser.set_defaults(debug=False)
  37. parser.set_defaults(url='http://localhost/rpc/api')
  38. (options, args) = parser.parse_args()
  39.  
  40.  
  41. if __name__ == '__main__':
  42.  
  43.     login = False
  44.     password = False
  45.  
  46.     # Read config file for options
  47.     if options.configfile:
  48.         config = ConfigParser.ConfigParser()
  49.         config.read(options.configfile)
  50.         try:
  51.             url = config.get('config','url')
  52.         except ConfigParser.NoOptionError:
  53.             pass
  54.         except ConfigParser.NoSectionError:
  55.             parser.print_help()
  56.             print
  57.             print >>sys.stderr, 'No config section found in your config file.'
  58.             print >>sys.stderr, 'Please verify that %s exists and has the correct syntax.' % (options.configfile)
  59.             sys.exit(1)
  60.         try:
  61.             login = config.get('config','login')
  62.         except ConfigParser.NoOptionError:
  63.             pass
  64.         try:
  65.             password = config.get('config','password')
  66.         except ConfigParser.NoOptionError:
  67.             pass
  68.  
  69.     url = options.url
  70.     debug = options.debug
  71.     if options.login:
  72.         login = options.login
  73.     if options.password:
  74.         password = options.password
  75.  
  76.     # Various checks up front to save time
  77.     if login and password:
  78.         client = xmlrpclib.Server(url, verbose=0)
  79.         authKey = client.auth.login(login, password)
  80.     else:
  81.         parser.print_help()
  82.         parser.error("Login or Password have not been defined on the commandline or in a config file")
  83.  
  84.     # Establish which system arch types to look for
  85.     rhel5_x64 = False
  86.     rhel4_x64 = False
  87.     rhel3_x64 = False
  88.     rhel5_i386 = False
  89.     rhel4_i386 = False
  90.     rhel3_i386 = False
  91.  
  92.     # get a list of servers to iterate over
  93.     if debug:
  94.         print >>sys.stderr, "Starting collection of system names"
  95.     active_systems = []
  96.     if args:
  97.         args.sort()
  98.         for system in args:
  99.             try:
  100.                 data = client.system.getId(authKey,system)[0]
  101.                 cpu = client.system.getCpu(authKey,data['id'])
  102.                 detail = client.system.getDetails(authKey,data['id'])
  103.                 if cpu['arch'] == 'x86_64':
  104.                     if detail['release'] == '5Server':
  105.                         rhel5_x64 = True
  106.                     if detail['release'] == '4AS':
  107.                         rhel4_x64 = True
  108.                     if detail['release'] == '3AS':
  109.                         rhel3_x64 = True
  110.                 if cpu['arch'] == 'i386' or cpu['arch'] == 'i686':
  111.                     if detail['release'] == '5Server':
  112.                         rhel5_i386 = True
  113.                     if detail['release'] == '4AS':
  114.                         rhel4_i386 = True
  115.                     if detail['release'] == '3AS':
  116.                         rhel3_i386 = True
  117.                 data['arch'] = cpu['arch']
  118.                 data['release'] = detail['release']
  119.                 active_systems.append(data)
  120.             except:
  121.                 print >>sys.stderr, "ERROR: Could not identify servername: %s" % system
  122.     else:
  123.         systems = sorted(client.system.listActiveSystems(authKey), key=lambda k: k['name'])
  124.         for system in systems:
  125.             data = system
  126.             cpu = client.system.getCpu(authKey,data['id'])
  127.             detail = client.system.getDetails(authKey,data['id'])
  128.             data['arch'] = cpu['arch']
  129.             data['release'] = detail['release']
  130.             active_systems.append(data)
  131.         rhel5_x64 = True
  132.         rhel4_x64 = True
  133.         rhel3_x64 = True
  134.         rhel5_i386 = True
  135.         rhel4_i386 = True
  136.         rhel3_i386 = True
  137.  
  138.     # ALL RHEL3-64 Packages
  139.     if rhel3_x64:
  140.         if debug:
  141.             print >>sys.stderr, "Starting collection of RHEL3 64bit"
  142.         rhel3 = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-3')
  143.         rhel3_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-3-as-x86_64')
  144.         rhel3_x64_all = rhel3 + rhel3_tools
  145.  
  146.     # ALL RHEL3-32 Packages
  147.     if rhel3_i386:
  148.         if debug:
  149.             print >>sys.stderr, "Starting collection of RHEL3 32bit"
  150.         rhel3 = client.channel.software.listAllPackages(authKey,'rhel-i386-as-3')
  151.         rhel3_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-3-as-i386')
  152.         rhel3_i386_all = rhel3 + rhel3_tools
  153.  
  154.     # ALL RHEL4-64 Packages
  155.     if rhel4_x64:
  156.         if debug:
  157.             print >>sys.stderr, "Starting collection of RHEL4 64bit"
  158.         rhel4 = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4')
  159.         rhel4_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-4-as-x86_64')
  160.         rhel4_cluster = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4-cluster')
  161.         rhel4_gfs = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4-gfs-6.1')
  162.         rhel4_proxy = client.channel.software.listAllPackages(authKey,'redhat-rhn-proxy-5.1-as-x86_64-4')
  163.         rhel4_extras = client.channel.software.listAllPackages(authKey,'rhel-x86_64-as-4-extras')
  164.         rhel4_x64_all = rhel4 + rhel4_tools + rhel4_cluster + rhel4_gfs + rhel4_proxy + rhel4_extras
  165.  
  166.     # ALL RHEL4-32 Packages
  167.     if rhel4_i386:
  168.         if debug:
  169.             print >>sys.stderr, "Starting collection of RHEL4 32bit"
  170.         rhel4 = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4')
  171.         rhel4_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-4-as-i386')
  172.         rhel4_cluster = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4-cluster')
  173.         rhel4_gfs = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4-gfs-6.1')
  174.         rhel4_proxy = client.channel.software.listAllPackages(authKey,'redhat-rhn-proxy-5.1-as-i386-4')
  175.         rhel4_extras = client.channel.software.listAllPackages(authKey,'rhel-i386-as-4-extras')
  176.         rhel4_i386_all = rhel4 + rhel4_tools + rhel4_cluster + rhel4_gfs + rhel4_proxy + rhel4_extras
  177.  
  178.     # ALL RHEL5-64 Packages
  179.     if rhel5_x64:
  180.         if debug:
  181.             print >>sys.stderr, "Starting collection of RHEL5 64bit"
  182.         rhel5 = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-5')
  183.         rhel5_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-x86_64-server-5')
  184.         rhel5_cluster_storage = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-cluster-storage-5')
  185.         rhel5_cluster = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-cluster-5')
  186.         rhel5_prod = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-productivity-5')
  187.         rhel5_supp = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-supplementary-5')
  188.         rhel5_virt = client.channel.software.listAllPackages(authKey,'rhel-x86_64-server-vt-5')
  189.         rhel5_x64_all = rhel5 + rhel5_tools + rhel5_cluster_storage + rhel5_cluster + rhel5_prod + rhel5_supp + rhel5_virt
  190.  
  191.     # ALL RHEL5-32 Packages
  192.     if rhel5_i386:
  193.         if debug:
  194.             print >>sys.stderr, "Starting collection of RHEL5 32bit"
  195.         rhel5 = client.channel.software.listAllPackages(authKey,'rhel-i386-server-5')
  196.         rhel5_proxy = client.channel.software.listAllPackages(authKey,'redhat-rhn-proxy-5.3-server-i386-5')
  197.         rhel5_tools = client.channel.software.listAllPackages(authKey,'rhn-tools-rhel-i386-server-5')
  198.         rhel5_cluster_storage = client.channel.software.listAllPackages(authKey,'rhel-i386-server-cluster-storage-5')
  199.         rhel5_cluster = client.channel.software.listAllPackages(authKey,'rhel-i386-server-cluster-5')
  200.         rhel5_prod = client.channel.software.listAllPackages(authKey,'rhel-i386-server-productivity-5')
  201.         rhel5_supp = client.channel.software.listAllPackages(authKey,'rhel-i386-server-supplementary-5')
  202.         rhel5_i386_all = rhel5 + rhel5_proxy + rhel5_tools + rhel5_cluster_storage + rhel5_cluster + rhel5_prod + rhel5_supp
  203.  
  204.     for system in active_systems:
  205.         # re-auth every system to avoid timeouts
  206.         authKey = client.auth.login(login, password)
  207.         system_package_list = client.system.listPackages(authKey,system['id'])
  208.         package_dict = {}
  209.         unmatched_packages = []
  210.         try:
  211.             if system['arch'] == 'x86_64':
  212.                 if system['release'] == '5Server':
  213.                     if debug:
  214.                         print >>sys.stderr, "RHEL5 64bit collected"
  215.                     base_package_list = rhel5_x64_all
  216.                 elif system['release'] == '4AS':
  217.                     if debug:
  218.                         print >>sys.stderr, "RHEL4 64bit collected"
  219.                     base_package_list = rhel4_x64_all
  220.                 else:
  221.                     if debug:
  222.                         print >>sys.stderr, "RHEL3 64bit collected"
  223.                     base_package_list = rhel3_x64_all
  224.             if system['arch'] == 'i386' or system['arch'] == 'i686':
  225.                 if system['release'] == '5Server':
  226.                     if debug:
  227.                         print >>sys.stderr, "RHEL5 32bit collected"
  228.                     base_package_list = rhel5_i386_all
  229.                 elif system['release'] == '4AS':
  230.                     if debug:
  231.                         print >>sys.stderr, "RHEL4 32bit collected"
  232.                     base_package_list = rhel4_i386_all
  233.                 else:
  234.                     if debug:
  235.                         print >>sys.stderr, "RHEL3 32bit collected"
  236.                     base_package_list = rhel3_i386_all
  237.         except:
  238.             base_package_list = []
  239.             print 'WARNING, Unable to find packages -- System: %s, Arch: %s, Release: %s' % (system['name'],
  240.                                                                                             system['arch'],
  241.                                                                                             system['release'],)
  242.             continue
  243.  
  244.         for package in system_package_list:
  245.             arch = getArch(package['arch'])
  246.             matched = False
  247.             for base_package in base_package_list:
  248.                 pname = package['name'] == base_package['name']
  249.                 parch = arch == base_package['arch_label']
  250.                 release = package['release'] == base_package['release']
  251.                 version = package['version'] == base_package['version']
  252.                 if pname:
  253.                     matched = True
  254.                     pkey = base_package['name']+base_package['arch_label']
  255.                     package_dict.setdefault(pkey,{})
  256.                     package_dict[pkey][base_package['id']] = {}
  257.                     package_dict[pkey][base_package['id']]['data'] = base_package
  258.                     if release and version:
  259.                         package_dict[pkey][base_package['id']]['current'] = True
  260.                     else:
  261.                         package_dict[pkey][base_package['id']]['current'] = False
  262.             if not matched:
  263.                 unmatched_packages.append(package['name']+'.'+package['arch'])
  264.  
  265.         bugfix_list = {}
  266.         security_list = {}
  267.         enhancement_list = {}
  268.  
  269.         package_keys = package_dict.keys()
  270.         package_keys.sort()
  271.         for package in package_keys:
  272.             get_advisory = False
  273.             current = 0
  274.             pkg = package_dict[package]
  275.             pkg_keys = pkg.keys()
  276.             pkg_keys.sort()
  277.             for pkey in pkg_keys:
  278.                 if pkg[pkey]['current']:
  279.                     if not pkey == pkg_keys[-1]:
  280.                         get_advisory = True
  281.                         current = pkg[pkey]['data']['id']
  282.                     continue
  283.                 if get_advisory:
  284.                     advisories = client.packages.listProvidingErrata(authKey,pkg[pkey]['data']['id'])
  285.                     for advisory in advisories:
  286.                         if 'RH' in advisory['advisory']:
  287.                             if 'Bug Fix Advisory' in advisory['type']:
  288.                                 try:
  289.                                     bugfix_list[advisory['advisory']].append(pkg[pkey]['data'])
  290.                                 except:
  291.                                     bugfix_list[advisory['advisory']] = []
  292.                                     bugfix_list[advisory['advisory']].append(pkg[pkey]['data'])
  293.                             if 'Security Advisory' in advisory['type']:
  294.                                 try:
  295.                                     security_list[advisory['advisory']].append(pkg[pkey]['data'])
  296.                                 except:
  297.                                     security_list[advisory['advisory']] = []
  298.                                     security_list[advisory['advisory']].append(pkg[pkey]['data'])
  299.                             if 'Product Enhancement Advisory' in advisory['type']:
  300.                                 try:
  301.                                     enhancement_list[advisory['advisory']].append(pkg[pkey]['data'])
  302.                                 except:
  303.                                     enhancement_list[advisory['advisory']] = []
  304.                                     enhancement_list[advisory['advisory']].append(pkg[pkey]['data'])
  305.                             #print 'ADVISORY ALERT %s:%s -- Package: %s %s %s, Base Package: %s %s %s' % (advisory['advisory'],
  306.                             #                                                                            advisory['type'],
  307.                             #                                                                            pkg[current]['data']['name'],
  308.                             #                                                                            pkg[current]['data']['version'],
  309.                             #                                                                            pkg[current]['data']['release'],
  310.                             #                                                                            pkg[pkey]['data']['name'],
  311.                             #                                                                            pkg[pkey]['data']['version'],
  312.                             #                                                                            pkg[pkey]['data']['release'])
  313.  
  314.         print 'System: %s, Arch: %s, Release: %s, Bugfixes: %d, Security Fixes: %d, Enhancements: %d' % (system['name'],
  315.                                                                                                 system['arch'],
  316.                                                                                                 system['release'],
  317.                                                                                                 len(bugfix_list),
  318.                                                                                                 len(security_list),
  319.                                                                                                 len(enhancement_list))
  320.         if debug:
  321.             print
  322.             print 'UNMATCHED PACKAGES'
  323.             pprint.pprint(unmatched_packages)
  324.             print
  325.             print 'BUGFIX LIST'
  326.             pprint.pprint(bugfix_list)
  327.             print
  328.             print 'SECURITY LIST'
  329.             pprint.pprint(security_list)
  330.             print
  331.             print 'ENHANCEMENT LIST'
  332.             pprint.pprint(enhancement_list)
  333.         sys.stdout.flush()
  334.  
  335.     client.auth.logout(authKey)
Advertisement
Add Comment
Please, Sign In to add comment