mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-27 09:21:59 -06:00
50a2c45760
Install tools may fail with unexpected error when IPA server is not installed on a system. Improve user experience by implementing a check to affected tools. https://fedorahosted.org/freeipa/ticket/1327 https://fedorahosted.org/freeipa/ticket/1347
201 lines
6.2 KiB
Python
201 lines
6.2 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Authors:
|
|
# Rob Crittenden <rcritten@redhat.com>
|
|
#
|
|
# Copyright (C) 2010 Red Hat
|
|
# see file 'COPYING' for use and warranty information
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# An LDAP client to count entitlements and log to syslog if the number is
|
|
# exceeded.
|
|
|
|
try:
|
|
import sys
|
|
import os
|
|
import syslog
|
|
import tempfile
|
|
import krbV
|
|
import base64
|
|
import shutil
|
|
|
|
from rhsm.certificate import EntitlementCertificate
|
|
|
|
from ipaserver.plugins.ldap2 import ldap2
|
|
from ipalib import api, errors, backend
|
|
from ipaserver.install import installutils
|
|
except ImportError, e:
|
|
# If python-rhsm isn't installed exit gracefully and quietly.
|
|
if e.args[0] == 'No module named rhsm.certificate':
|
|
sys.exit(0)
|
|
print >> sys.stderr, """\
|
|
There was a problem importing one of the required Python modules. The
|
|
error was:
|
|
|
|
%s
|
|
""" % sys.exc_value
|
|
sys.exit(1)
|
|
|
|
# Each IPA server comes with this many entitlements
|
|
DEFAULT_ENTITLEMENTS = 25
|
|
|
|
class client(backend.Executioner):
|
|
"""
|
|
A simple-minded IPA client that can execute remote commands.
|
|
"""
|
|
|
|
def run(self, method, **kw):
|
|
self.create_context()
|
|
result = self.execute(method, **kw)
|
|
return result
|
|
|
|
def parse_options():
|
|
from optparse import OptionParser
|
|
|
|
parser = OptionParser()
|
|
parser.add_option("--debug", dest="debug", action="store_true",
|
|
default=False, help="enable debugging")
|
|
|
|
options, args = parser.parse_args()
|
|
return options, args
|
|
|
|
def check_compliance(tmpdir, debug=False):
|
|
cfg = dict(
|
|
context='cli',
|
|
in_server=False,
|
|
debug=debug,
|
|
verbose=0,
|
|
)
|
|
|
|
api.bootstrap(**cfg)
|
|
api.register(client)
|
|
api.finalize()
|
|
from ipalib.x509 import normalize_certificate, make_pem
|
|
|
|
try:
|
|
# Create a new credentials cache for this tool. This executes
|
|
# using the systems host principal.
|
|
ccache_file = 'FILE:%s/ccache' % tmpdir
|
|
krbcontext = krbV.default_context()
|
|
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
|
|
keytab = krbV.Keytab(name='/etc/krb5.keytab', context=krbcontext)
|
|
principal = krbV.Principal(name=principal, context=krbcontext)
|
|
os.environ['KRB5CCNAME'] = ccache_file
|
|
ccache = krbV.CCache(name=ccache_file, context=krbcontext, primary_principal=principal)
|
|
ccache.init(principal)
|
|
ccache.init_creds_keytab(keytab=keytab, principal=principal)
|
|
except krbV.Krb5Error, e:
|
|
raise StandardError('Error initializing principal %s in %s: %s' % (principal.name, '/etc/krb5.keytab', str(e)))
|
|
|
|
# entitle-sync doesn't return any information we want to see, it just
|
|
# needs to be done so the LDAP data is correct.
|
|
try:
|
|
result = api.Backend.client.run('entitle_sync')
|
|
except errors.NotRegisteredError:
|
|
# Even if not registered they have some default entitlements
|
|
pass
|
|
|
|
conn = ldap2(shared_instance=False)
|
|
|
|
# Bind using GSSAPI
|
|
conn.connect(ccache=ccache_file)
|
|
|
|
hostcount = 0
|
|
# Get the hosts first
|
|
try:
|
|
(entries, truncated) = conn.find_entries('(krblastpwdchange=*)', ['dn'],
|
|
'%s,%s' % (api.env.container_host, api.env.basedn),
|
|
conn.SCOPE_ONELEVEL,
|
|
size_limit = -1)
|
|
except errors.NotFound:
|
|
# No hosts
|
|
pass
|
|
|
|
if not truncated:
|
|
hostcount = len(entries)
|
|
else:
|
|
# This will not happen unless we bump into a server-side limit.
|
|
msg = 'The host count result was truncated, they will be underreported'
|
|
syslog.syslog(syslog.LOG_ERR, msg)
|
|
if sys.stdin.isatty():
|
|
print msg
|
|
|
|
available = 0
|
|
try:
|
|
(entries, truncated) = conn.find_entries('(objectclass=ipaentitlement)',
|
|
['dn', 'userCertificate'],
|
|
'%s,%s' % (api.env.container_entitlements, api.env.basedn),
|
|
conn.SCOPE_ONELEVEL,
|
|
size_limit = -1)
|
|
|
|
for entry in entries:
|
|
(dn, attrs) = entry
|
|
if 'usercertificate' in attrs:
|
|
rawcert = attrs['usercertificate'][0]
|
|
rawcert = normalize_certificate(rawcert)
|
|
cert = make_pem(base64.b64encode(rawcert))
|
|
cert = EntitlementCertificate(cert)
|
|
order = cert.getOrder()
|
|
available += int(order.getQuantityUsed())
|
|
except errors.NotFound:
|
|
pass
|
|
|
|
conn.disconnect()
|
|
|
|
available += DEFAULT_ENTITLEMENTS
|
|
|
|
if hostcount > available:
|
|
syslog.syslog(syslog.LOG_ERR, 'IPA is out of compliance: %d of %d entitlements used.' % (hostcount, available))
|
|
if sys.stdin.isatty():
|
|
print 'IPA is out of compliance: %d of %d entitlements used.' % (hostcount, available)
|
|
else:
|
|
if sys.stdin.isatty():
|
|
# If run from the command-line display some info
|
|
print 'IPA is in compliance: %d of %d entitlements used.' % (hostcount, available)
|
|
|
|
def main():
|
|
installutils.check_server_configuration()
|
|
|
|
if not os.path.exists('/etc/ipa/default.conf'):
|
|
return 0
|
|
|
|
options, args = parse_options()
|
|
|
|
try:
|
|
tmpdir = tempfile.mkdtemp(prefix = "tmp-")
|
|
try:
|
|
check_compliance(tmpdir, options.debug)
|
|
finally:
|
|
shutil.rmtree(tmpdir)
|
|
except KeyboardInterrupt:
|
|
return 1
|
|
except (StandardError, errors.PublicError), e:
|
|
syslog.syslog(syslog.LOG_ERR, 'IPA compliance checking failed: %s' % str(e))
|
|
if sys.stdin.isatty():
|
|
print 'IPA compliance checking failed: %s' % str(e)
|
|
return 1
|
|
|
|
return 0
|
|
|
|
try:
|
|
if not os.geteuid()==0:
|
|
sys.exit("\nMust be root to check compliance\n")
|
|
|
|
main()
|
|
except SystemExit, e:
|
|
sys.exit(e)
|
|
except RuntimeError, e:
|
|
sys.exit(e)
|