Module scap
[hide private]
[frames] | no frames]

Source Code for Module scap

  1   
  2  import sys 
  3  import os 
  4  import subprocess 
  5  import xml.sax 
  6  import tempfile 
  7  import shutil 
  8  from base64 import encodestring 
  9  from up2date_client import up2dateLog 
 10  from up2date_client import rhnserver 
 11  from up2date_client import up2dateAuth 
 12  from up2date_client import up2dateErrors 
 13  from rhn.i18n import sstr, bstr 
 14   
 15  __rhnexport__ = [ 'xccdf_eval' ] 
 16   
 17  log = up2dateLog.initLog() 
 18   
19 -def xccdf_eval(args, cache_only=None):
20 if cache_only: 21 return (0, 'no-ops for caching', {}) 22 23 results_dir = None 24 if ('id' in args) and ('file_size' in args) and args['file_size'] > 0: 25 results_dir = tempfile.mkdtemp() 26 pwd = os.getcwd() 27 os.chdir(results_dir) 28 29 results_file = tempfile.NamedTemporaryFile(dir=results_dir) 30 params, oscap_err = _process_params(args['params'], results_file.name, results_dir) 31 32 oscap_err += _run_oscap(['xccdf', 'eval'] + params + [args['path']]) 33 if results_dir: 34 os.chdir(pwd) 35 36 if not _assert_xml(results_file.file): 37 del(results_file) 38 _cleanup_temp(results_dir) 39 return (1, 'oscap tool did not produce valid xml.\n' + oscap_err, {}) 40 41 ret, resume, xslt_err = _xccdf_resume(results_file.name, temp_dir=results_dir) 42 if ret != 0 or resume == '': 43 del(results_file) 44 _cleanup_temp(results_dir) 45 return (1, 'Problems with extracting resume:\n' + xslt_err, {}) 46 47 try: 48 up_err = _upload_results(results_file, results_dir, args) 49 except: 50 # An error during the upload must not prevent scan completion 51 log.log_exception(*sys.exc_info()) 52 up_err = "Upload of detailed results failed. Fatal error in Python code occurred" 53 del(results_file) 54 _cleanup_temp(results_dir) 55 return (0, 'openscap scan completed', { 56 'resume': encodestring(resume), 57 'errors': encodestring(bstr(oscap_err) + bstr(xslt_err) + bstr(up_err)) 58 })
59
60 -def _run_oscap(arguments):
61 dev_null = open('/dev/null', mode="ab+") 62 c = _popen(['/usr/bin/oscap'] + arguments, stdout=dev_null.fileno()) 63 ret = c.wait() 64 dev_null.close() 65 errors = sstr(c.stderr.read()) 66 if ret != 0: 67 errors += 'xccdf_eval: oscap tool returned %i\n' % ret 68 log.log_debug('The oscap tool completed\n%s' % errors) 69 return errors
70
71 -def _xccdf_resume(results_file, temp_dir=None):
72 xslt = '/usr/share/openscap/xsl/xccdf-resume.xslt' 73 74 dev_null = open('/dev/null', mode="ab+") 75 resume_file = tempfile.NamedTemporaryFile(dir=temp_dir) 76 c = _popen(['/usr/bin/xsltproc', '--output', resume_file.name, 77 xslt, results_file], stdout=dev_null.fileno()) 78 ret = c.wait() 79 dev_null.close() 80 81 errors = sstr(c.stderr.read()) 82 if ret != 0: 83 errors += 'xccdf_eval: xsltproc tool returned %i\n' % ret 84 log.log_debug('The xsltproc tool completed:\n%s' % errors) 85 86 resume = resume_file.read() 87 del(resume_file) 88 return ret, resume, errors
89
90 -def _popen(args, stdout=subprocess.PIPE):
91 log.log_debug('Running: ' + str(args)) 92 return subprocess.Popen(args, bufsize=-1, stdin=subprocess.PIPE, 93 stdout=stdout, stderr=subprocess.PIPE, shell=False)
94
95 -def _process_params(args, filename, results_dir=None):
96 params = ['--results', filename] 97 if results_dir: 98 params += ['--oval-results', '--report', 'xccdf-report.html'] 99 errors = '' 100 if args: 101 allowed_args = { 102 '--profile': 1, 103 '--skip-valid': 0, 104 '--cpe': 1, 105 '--fetch-remote-resources': 0, 106 '--datastream-id': 1, 107 '--xccdf-id': 1, 108 '--tailoring-id': 1, 109 '--tailoring-file': 1, 110 } 111 args = args.split(' ') 112 i = 0 113 while i < len(args): 114 if args[i] in allowed_args: 115 j = i + allowed_args[args[i]] 116 params += args[i:j+1] 117 i = j 118 elif not errors: 119 errors = 'xccdf_eval: Following arguments forbidden: ' + args[i] 120 else: 121 errors += ' ' + args[i] 122 i += 1 123 if errors: 124 errors += '\n' 125 return params, errors
126
127 -def _upload_results(xccdf_result, results_dir, args):
128 errors = '' 129 if results_dir: 130 server = rhnserver.RhnServer() 131 # No need to check capabilities. The server supports detailed results 132 # If rhe 'file_size' and 'id' was in supplied in the argument list. 133 systemid = up2dateAuth.getSystemId() 134 for filename in os.listdir(results_dir): 135 path = os.path.join(results_dir, filename) 136 if path == xccdf_result.name: 137 f = xccdf_result.file 138 filename = "xccdf-results.xml" 139 else: 140 f = open(path, 'rb') 141 errors += _upload_file(server, systemid, args, path, filename, f) 142 if path != xccdf_result.name: 143 f.close() 144 return errors
145
146 -def _upload_file(server, systemid, args, path, filename, f):
147 if filename != 'xccdf-report.html' and not _assert_xml(f): 148 log.log_debug('Excluding "%s" file from upload. Not an XML.' % path) 149 return '\nxccdf_eval: File "%s" not uploaded. Not an XML file format.' % filename 150 151 stat = os.fstat(f.fileno()) 152 if stat.st_size < args['file_size']: 153 try: 154 ret = server.scap.upload_result(systemid, args['id'], 155 {'filename': filename, 156 'filecontent': encodestring(f.read()), 157 'content-encoding': 'base64', 158 }) 159 if ret and ret['result']: 160 log.log_debug('The file %s uploaded successfully.' % filename) 161 return '' 162 except up2dateErrors.Error: 163 e = sys.exc_info()[1] 164 log.log_exception(*sys.exc_info()) 165 return '\nxccdf_eval: File "%s" not uploaded. %s' % (filename, e) 166 else: 167 return '\nxccdf_eval: File "%s" not uploaded. File size (%d B) exceeds the limit.' \ 168 % (filename, stat.st_size)
169
170 -def _cleanup_temp(results_dir):
171 if results_dir: 172 shutil.rmtree(results_dir)
173
174 -def _assert_xml(f):
175 try: 176 try: 177 content = f.read() 178 xml.sax.parseString(content, xml.sax.ContentHandler()) 179 return True 180 except Exception: 181 log.log_exception(*sys.exc_info()) 182 return False 183 finally: 184 f.seek(0)
185