Gentoo Archives: gentoo-commits

From: Alex Legler <a3li@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/security:master commit in: bin/
Date: Wed, 01 Jun 2016 17:57:33
Message-Id: 1464803804.1e03a6b7d241a9eaa3f9950613b37d8c100602d1.a3li@gentoo
1 commit: 1e03a6b7d241a9eaa3f9950613b37d8c100602d1
2 Author: Alex Legler <alex <AT> a3li <DOT> li>
3 AuthorDate: Wed Jun 1 17:56:44 2016 +0000
4 Commit: Alex Legler <a3li <AT> gentoo <DOT> org>
5 CommitDate: Wed Jun 1 17:56:44 2016 +0000
6 URL: https://gitweb.gentoo.org/proj/security.git/commit/?id=1e03a6b7
7
8 Add initial CVETool CLI utility
9
10 bin/cvetool | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 1 file changed, 130 insertions(+)
12
13 diff --git a/bin/cvetool b/bin/cvetool
14 new file mode 100755
15 index 0000000..8e388e0
16 --- /dev/null
17 +++ b/bin/cvetool
18 @@ -0,0 +1,130 @@
19 +#!/usr/bin/env python3
20 +# Copyright 2016 Alex Legler
21 +# Distributed under the terms of the GNU General Public License v3
22 +
23 +import json
24 +import re
25 +import string
26 +import sys
27 +import os
28 +import httplib2
29 +from base64 import b64encode
30 +
31 +URI_BASE = 'https://glsamaker.gentoo.org'
32 +
33 +class CVETool:
34 + """ Interface to GLSAMaker's CVETool """
35 +
36 + def __init__(self, auth, command, args):
37 + self.auth = auth
38 +
39 + if command == 'info':
40 + self.info(self.cleanup_cve(sys.argv[2]))
41 + elif command == 'assign':
42 + if len(args) < 2:
43 + print('Usage: assign <bug> <CVE> [<CVE>...]')
44 + print('Assigns a set of CVEs to a bug')
45 + sys.exit(1)
46 +
47 + self.assign(args[0], [self.cleanup_cve(cve) for cve in args[1:]])
48 + elif command == 'nfu':
49 + if len(args) != 1:
50 + print('Usage: nfu <CVE>')
51 + print('Marks a CVE as not-for-us')
52 + sys.exit(1)
53 +
54 + self.nfu(self.cleanup_cve(args[0]))
55 + elif command == 'pw':
56 + if len(sys.argv) != 4:
57 + print('Usage: pw <user> <password>')
58 + print('Generates a base64-encoded credential for storing')
59 + sys.exit(1)
60 +
61 + self.pw(sys.argv[2], sys.argv[3])
62 + else:
63 + self.usage(sys.argv[0])
64 + sys.exit(1)
65 +
66 + def info(self, cve):
67 + data = self.json_request('/cve/info/' + cve + '.json')
68 +
69 + print(' CVE ID: ' + data['cve_id'])
70 + print(' Summary: ' + data['summary'])
71 + print(' Published: ' + data['published_at'])
72 + print('-' * 80)
73 + print(' State: ' + data['state'])
74 + print(' Bugs: ' + ' , '.join(['https://bugs.gentoo.org/' + str(bug) for bug in data['bugs']]))
75 +
76 + def assign(self, bug, cves):
77 + cve_ids = [self.get_internal_cve_id(cve) for cve in cves]
78 + response = self.request('/cve/assign/?bug=' + str(bug) + '&cves=' + ','.join([str(c) for c in cve_ids]))
79 +
80 + if (response == 'ok'):
81 + print('Assigned bug {} to {}'.format(str(bug), ', '.join(cves)))
82 + else:
83 + print('Assigning likely failed: ' + response)
84 + sys.exit(1)
85 +
86 + def nfu(self, cve):
87 + cve_id = self.get_internal_cve_id(cve)
88 + response = self.request('/cve/nfu/?cves=' + str(cve_id) + '&reason=')
89 +
90 + if (response == 'ok'):
91 + print('Marked {} as NFU'.format(cve))
92 + else:
93 + print('Assigning likely failed: ' + response)
94 + sys.exit(1)
95 +
96 +
97 + def usage(self, programname):
98 + """ Print usage information """
99 + print('Usage: {} <command> <cve> [args]'.format(programname))
100 + print('CLI for CVETool.')
101 +
102 + def pw(self, user, password):
103 + print(b64encode(bytes(user + ':' + password, 'utf-8')).decode('ascii'))
104 +
105 + def get_internal_cve_id(self, cve):
106 + """ Resolves a CVE id to the internal databse ID """
107 + return self.json_request('/cve/info/' + cve + '.json')['id']
108 +
109 + def json_request(self, uri, method='GET'):
110 + return json.loads(self.request(uri, method))
111 +
112 + def cleanup_cve(self, str):
113 + regex = re.compile('^(CVE-)?\d{4}-\d{4,}$')
114 + if not regex.match(str):
115 + raise ValueError('Cannot parse CVE: ' + str)
116 +
117 + if not str.startswith('CVE-'):
118 + return 'CVE-' + str
119 + else:
120 + return str
121 +
122 + def request(self, uri, method='GET'):
123 + client = httplib2.Http('.cache')
124 + full_uri = URI_BASE + uri
125 + response, content = client.request(full_uri, method, headers = { 'Authorization': 'Basic ' + self.auth })
126 +
127 + status = response['status']
128 + if (status[0] != '2' and status != '304'):
129 + raise RuntimeError(full_uri + ': ' + status)
130 +
131 + return content.decode('utf-8')
132 +
133 +def main():
134 + if not 'CVETOOL_AUTH' in os.environ and not sys.argv[1] == 'pw':
135 + print('CVETOOL_AUTH environment variable missing. Generate its contents with the pw subcommand.')
136 + sys.exit(1)
137 +
138 + auth = None
139 + if 'CVETOOL_AUTH' in os.environ:
140 + auth = os.environ['CVETOOL_AUTH']
141 +
142 + CVETool(auth, sys.argv[1], sys.argv[2:])
143 +
144 +if __name__ == "__main__":
145 + try:
146 + main()
147 + except KeyboardInterrupt:
148 + print('\n ! Exiting.')