1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import os
18 import sys
19 import time
20 import tempfile
21 import re
22 from optparse import Option, OptionParser
23 from M2Crypto import X509
24
25 from rhn.connections import idn_ascii_to_puny
26
27 try:
28 from rhsm.config import RhsmConfigParser
29 except ImportError:
30 RhsmConfigParser = None
31
32
33 from spacewalk.common import fileutils, rhnLog
34 from spacewalk.common.rhnConfig import CFG, initCFG, PRODUCT_NAME
35 from spacewalk.common.rhnTranslate import _
36 from spacewalk.server.rhnServer import satellite_cert
37
38 try:
39 from spacewalk.cdn_tools import activation as cdn_activation
40 from spacewalk.cdn_tools.manifest import MissingSatelliteCertificateError, ManifestValidationError,\
41 IncorrectEntitlementsFileFormatError
42 from spacewalk.cdn_tools.common import CdnMappingsLoadError
43 except ImportError:
44 cdn_activation = None
45 MissingSatelliteCertificateError = None
46 ManifestValidationError = None
47 CdnMappingsLoadError = None
48 from spacewalk.satellite_tools.syncLib import log, log2disk, log2
49
50
51 DEFAULT_RHSM_MANIFEST_LOCATION = '/etc/sysconfig/rhn/rhsm-manifest.zip'
52 DEFAULT_WEBAPP_GPG_KEY_RING = "/etc/webapp-keyring.gpg"
53 DEFAULT_CONFIG_FILE = "/etc/rhn/rhn.conf"
54 DEFAULT_RHSM_CONFIG_FILE = "/etc/rhsm/rhsm.conf"
55 SUPPORTED_RHEL_VERSIONS = ['5', '6']
56 LOG_PATH = '/var/log/rhn/activation.log'
57
58
60 log2(0, 0, '\nERROR: %s\n' % e, stream=sys.stderr, cleanYN=1)
61
62
64 "raise when fail to insert CA cert into the local database"
65
66
68 """ Tries to get UUID of of this system if it's registered into Subscription manager."""
69
70 if RhsmConfigParser and os.path.isfile(DEFAULT_RHSM_CONFIG_FILE):
71 cfg = RhsmConfigParser(config_file=DEFAULT_RHSM_CONFIG_FILE)
72 cert_dir = cfg.get('rhsm', 'consumerCertDir')
73 cert_path = os.path.join(cert_dir, 'cert.pem')
74 if os.path.isfile(cert_path):
75 f = open(cert_path, 'r')
76 cert = X509.load_cert_string(f.read())
77 f.close()
78 subject = cert.get_subject()
79 return subject.CN
80 return None
81
82
85
86
88 result = ""
89 tree = {}
90
91
92 for field in sat_cert.fields_scalar:
93 tree[field] = getattr(sat_cert, field)
94
95 for name, value in sat_cert.fields_list.items():
96 field = value.attribute_name
97 tree[name] = []
98 for item in getattr(sat_cert, field):
99 attributes = {}
100 for k, v in item.attributes.items():
101 attr = getattr(item, v)
102 if attr != "":
103 attributes[k] = attr
104 tree[name].append(attributes)
105
106
107 for key in sorted(tree):
108 if isinstance(tree[key], list):
109 for item in sorted(tree[key], key=lambda item: "".join(sorted(item.keys() + item.values()))):
110 line = "%s" % key
111 for attribute in sorted(item):
112 line += "-%s-%s" % (attribute, item[attribute])
113 result += "%s\n" % line
114 else:
115 if tree[key] is not None:
116 result += "%s-%s\n" % (key, tree[key])
117
118 return result
119
120
122 """ validating (i.e., verifing sanity of) this product.
123 I.e., makes sure the product Certificate is a sane certificate
124 """
125
126 sat_cert = satellite_cert.SatelliteCert()
127 sat_cert.load(cert)
128
129 for key in ['generation', 'product', 'owner', 'issued', 'expires', 'slots']:
130 if not getattr(sat_cert, key):
131 writeError("Your satellite certificate is not valid. Field %s is not defined.\n"
132 "Please contact your support representative." % key)
133 raise RHNCertGeneralSanityException("RHN Entitlement Certificate failed "
134 "to validate.")
135
136 signature = sat_cert.signature
137
138
139 fd, certTmpFile = tempfile.mkstemp(prefix="/tmp/cert-")
140 fo = os.fdopen(fd, 'wb')
141 fo.write(getCertChecksumString(sat_cert))
142 fo.flush()
143 fo.close()
144
145 fd, signatureTmpFile = tempfile.mkstemp(prefix="/tmp/cert-signature-")
146 fo = os.fdopen(fd, 'wb')
147 fo.write(signature)
148 fo.flush()
149 fo.close()
150
151 args = ['gpg', '--verify', '-q', '--keyring',
152 DEFAULT_WEBAPP_GPG_KEY_RING, signatureTmpFile, certTmpFile]
153
154 log(1, "Checking cert XML sanity and GPG signature: %s" % repr(' '.join(args)))
155
156 ret, out, err = fileutils.rhn_popen(args)
157 err = err.read()
158 out = out.read()
159
160
161 os.unlink(certTmpFile)
162 os.unlink(signatureTmpFile)
163
164 if err.find('Ohhhh jeeee: ... this is a bug') != -1 or err.find('verify err') != -1 or ret:
165 msg = "%s Entitlement Certificate failed to validate.\n" % PRODUCT_NAME
166 msg += "MORE INFORMATION:\n"
167 msg = msg + " Return value: %s\n" % ret +\
168 " Standard-out: %s\n" % out +\
169 " Standard-error: %s" % err
170 writeError(msg)
171 raise RHNCertGeneralSanityException("RHN Entitlement Certificate failed "
172 "to validate.")
173 return 0
174
175
186
187
208
209
211 args = ['rpm', '-q', '--qf', '\'%{version} %{arch}\'', '-f', '/etc/redhat-release']
212 ret, out, err = fileutils.rhn_popen(args)
213 data = out.read().strip("'")
214 version, arch = data.split()
215
216 version = re.search(r'\d+', version).group()
217
218 if version not in SUPPORTED_RHEL_VERSIONS:
219 log(0, "WARNING: No Satellite repository available for RHEL version: %s." % version)
220 return
221
222 arch_str = "server"
223 if arch == "s390x":
224 arch_str = "system-z"
225
226 sat_cert = satellite_cert.SatelliteCert()
227 sat_cert.load(rhn_cert)
228 sat_version = getattr(sat_cert, 'satellite-version')
229
230 repo = "rhel-%s-%s-satellite-%s-rpms" % (version, arch_str, sat_version)
231 args = ['/usr/bin/subscription-manager', 'repos', '--enable', repo]
232 ret, out, err = fileutils.rhn_popen(args)
233 if ret:
234 msg_ = "Enabling of Satellite repository failed."
235 msg = ("%s\nReturn value: %s\nStandard-out: %s\n\n"
236 "Standard-error: %s\n"
237 % (msg_, ret, out.read(), err.read()))
238 writeError(msg)
239 raise EnableSatelliteRepositoryException("Enabling of Satellite repository failed. Make sure Satellite "
240 "subscription is attached to this system, both versions of RHEL and "
241 "Satellite are supported or run activation with --disconnected "
242 "option.")
243
244
246 "when there is no attached satellite subscription in rhsm or incorrect combination of rhel and sat version"
247
248
250 """ dead simple check to see if our RHN cert is not expired
251 returns either "" or the date of expiration.
252 """
253
254
255 sc = satellite_cert.SatelliteCert()
256 sc.load(cert)
257
258
259 try:
260 expires = time.mktime(time.strptime(sc.expires, sc.datesFormat_cert))-time.timezone
261 except ValueError:
262 writeError("Can't seem to parse the expires field in the RHN Certificate. "
263 "RHN Certificate's version is incorrect?")
264
265 sys.exit(11)
266
267 now = time.time()
268 if expires < now:
269 return sc.expires
270 else:
271 return ''
272
273
275 options = [
276 Option('--sanity-only', action='store_true', help="confirm certificate sanity. Does not activate "
277 + "the Red Hat Satellite locally or remotely."),
278 Option('--ignore-expiration', action='store_true', help='execute regardless of the expiration '
279 + 'of the RHN Certificate (not recommended).'),
280 Option('--ignore-version-mismatch', action='store_true', help='execute regardless of version '
281 + 'mismatch of existing and new certificate.'),
282 Option('-v', '--verbose', action='count', help='be verbose '
283 + '(accumulable: -vvv means "be *really* verbose").'),
284 Option('--dump-version', action='store', help="requested version of XML dump"),
285 Option('--manifest', action='store', help='the RHSM manifest path/filename to activate for CDN'),
286 Option('--rhn-cert', action='store', help='this option is deprecated, use --manifest instead'),
287 Option('--deactivate', action='store_true', help='deactivate CDN-activated Satellite'),
288 Option('--disconnected', action='store_true', help="activate locally, not subscribe to remote repository"),
289 Option('--manifest-info', action='store_true', help="show information about currently activated manifest"),
290 Option('--manifest-download', action='store_true',
291 help="download new manifest from RHSM to temporary location"),
292 Option('--manifest-refresh', action='store_true', help="download new manifest from RHSM and activate it"),
293 Option('--manifest-reconcile-request', action='store_true',
294 help="request regeneration of entitlement certificates")
295 ]
296
297 parser = OptionParser(option_list=options)
298 options, args = parser.parse_args()
299
300 initCFG('server.satellite')
301 if options.verbose is None:
302 options.verbose = 0
303 CFG.set('DEBUG', options.verbose)
304 rhnLog.initLOG(LOG_PATH, options.verbose)
305 log2disk(0, "Command: %s" % str(sys.argv))
306
307
308 if args:
309 writeError("These arguments make no sense in this context (try --help): %s" % repr(args))
310 sys.exit(1)
311
312
313 if options.deactivate:
314 return options
315
316 if options.sanity_only:
317 options.disconnected = 1
318
319 if options.manifest_refresh:
320 options.manifest_download = 1
321
322 if CFG.DISCONNECTED and not options.disconnected:
323 msg = """Satellite server has been setup to run in disconnected mode.
324 Either correct server configuration in /etc/rhn/rhn.conf
325 or use --disconnected to activate it locally."""
326 writeError(msg)
327 sys.exit(1)
328
329 options.http_proxy = idn_ascii_to_puny(CFG.HTTP_PROXY)
330 options.http_proxy_username = CFG.HTTP_PROXY_USERNAME
331 options.http_proxy_password = CFG.HTTP_PROXY_PASSWORD
332 log(1, 'HTTP_PROXY: %s' % options.http_proxy)
333 log(1, 'HTTP_PROXY_USERNAME: %s' % options.http_proxy_username)
334 log(1, 'HTTP_PROXY_PASSWORD: <password>')
335
336 return options
337
338
339
340
342 """ main routine
343 1 general failure
344 10 general sanity check failure (to include a remedial cert
345 version check)
346 11 expired!
347 12 certificate version fails remedially
348 13 certificate missing in manifest
349 14 manifest signature incorrect
350 15 cannot load mapping files
351 16 manifest download failed
352 17 manifest refresh failed
353 18 manifest entitlements parse failed
354 30 local activation failure
355
356 90 not registered to rhsm
357 91 enabling sat repo failed
358
359 127 general unknown failure (not really mapped yet)
360
361 FIXME - need to redo how we process error codes - very manual
362 """
363
364
365 options = processCommandline()
366
367 if not cdn_activation:
368 writeError("Package spacewalk-backend-cdn has to be installed for using this tool.")
369 sys.exit(1)
370
371
372 if options.deactivate:
373 cdn_activation.Activation.deactivate()
374
375 if os.path.exists(DEFAULT_RHSM_MANIFEST_LOCATION):
376 fileutils.rotateFile(DEFAULT_RHSM_MANIFEST_LOCATION, depth=5)
377 os.unlink(DEFAULT_RHSM_MANIFEST_LOCATION)
378 return 0
379
380 if options.rhn_cert:
381 writeError("Activation with RHN Classic Satellite Certificate is deprecated.\nPlease obtain a Manifest for this"
382 " Satellite version via https://access.redhat.com/knowledge/tools/satcert, "
383 "and re-run this activation tool with option --manifest=MANIFEST-FILE.")
384 sys.exit(1)
385
386 if not options.manifest:
387 if os.path.exists(DEFAULT_RHSM_MANIFEST_LOCATION):
388 options.manifest = DEFAULT_RHSM_MANIFEST_LOCATION
389 if options.manifest_info:
390 cdn_activation.Activation.manifest_info(DEFAULT_RHSM_MANIFEST_LOCATION)
391 return 0
392
393 if options.manifest_reconcile_request:
394 log(0, "Requesting manifest regeneration...")
395 ok = cdn_activation.Activation.refresh_manifest(
396 DEFAULT_RHSM_MANIFEST_LOCATION,
397 http_proxy=options.http_proxy,
398 http_proxy_username=options.http_proxy_username,
399 http_proxy_password=options.http_proxy_password)
400 if not ok:
401 writeError("Manifest regeneration failed!")
402 return 17
403 log(0, "Manifest regeneration requested.")
404 return 0
405
406 if options.manifest_download:
407 log(0, "Downloading manifest...")
408 path = cdn_activation.Activation.download_manifest(
409 DEFAULT_RHSM_MANIFEST_LOCATION,
410 http_proxy=options.http_proxy,
411 http_proxy_username=options.http_proxy_username,
412 http_proxy_password=options.http_proxy_password)
413 if not path:
414 writeError("Manifest download failed!")
415 return 16
416 if options.manifest_refresh:
417 options.manifest = path
418 else:
419 log(0, "New manifest saved to: '%s'" % path)
420 return 0
421 else:
422 writeError("No currently activated manifest was found. "
423 "Run the activation tool with option --manifest=MANIFEST.")
424 return 1
425
426 try:
427 cdn_activate = cdn_activation.Activation(options.manifest)
428 except CdnMappingsLoadError, e:
429 writeError(e)
430 return 15
431 except MissingSatelliteCertificateError, e:
432 writeError(e)
433 return 13
434 except IncorrectEntitlementsFileFormatError, e:
435 writeError(e)
436 return 18
437
438
439 try:
440 validateSatCert(cdn_activate.manifest.get_satellite_certificate())
441 except RHNCertGeneralSanityException, e:
442 writeError(e)
443 return 10
444
445
446 if not options.ignore_expiration:
447 date = expiredYN(cdn_activate.manifest.get_satellite_certificate())
448 if date:
449 just_date = date.split(' ')[0]
450 writeError(
451 'Satellite Certificate appears to have expired: %s' % just_date)
452 return 11
453
454 if options.sanity_only:
455 return 0
456
457 if not options.disconnected:
458 rhsm_uuid = getRHSMUuid()
459 if not rhsm_uuid:
460 writeError("System not registered to RHSM? No identity found. Please register system to RHSM"
461 " or run activation with --disconnected option.")
462 return 90
463 try:
464 enableSatelliteRepo(cdn_activate.manifest.get_satellite_certificate())
465 except EnableSatelliteRepositoryException:
466 e = sys.exc_info()[1]
467 writeError(e)
468 return 91
469
470 try:
471 cdn_activate.activate()
472 except ManifestValidationError:
473 e = sys.exc_info()[1]
474 writeError(e)
475 return 14
476
477 storeRhsmManifest(options)
478
479 return 0
480
481
482
483 if __name__ == "__main__":
484 sys.stderr.write('\nWARNING: intended to be wrapped by another executable\n'
485 ' calling program.\n')
486 sys.exit(abs(main() or 0))
487
488