#!/usr/bin/python2 # Authors: # Christian Heimes # # Copyright (C) 2015 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 . # """ipa-httpd-kdproxy This script creates or removes the symlink from /etc/ipa/ipa-kdc-proxy.conf to /etc/httpd/conf.d/. It's called from ExecStartPre hook in httpd.service. """ import os import sys from ipalib import api, errors from ipapython.ipa_log_manager import standard_logging_setup from ipapython.ipaldap import IPAdmin from ipapython.dn import DN from ipaplatform.paths import paths DEBUG = False TIME_LIMIT = 2 class CheckError(Exception): """An unrecoverable error has occured""" class KDCProxyConfig(object): ipaconfig_flag = 'ipaKDCProxyEnabled' def __init__(self, time_limit=TIME_LIMIT): self.time_limit = time_limit self.con = None self.log = api.log self.ldap_uri = api.env.ldap_uri self.kdc_dn = DN(('cn', 'KDC'), ('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) self.conf = paths.HTTPD_IPA_KDCPROXY_CONF self.conflink = paths.HTTPD_IPA_KDCPROXY_CONF_SYMLINK def _ldap_con(self): """Establish LDAP connection""" self.log.debug('ldap_uri: %s', self.ldap_uri) try: self.con = IPAdmin(ldap_uri=self.ldap_uri) # EXTERNAL bind as root user self.con.ldapi = True self.con.do_bind(timeout=self.time_limit) except errors.NetworkError as e: msg = 'Failed to get setting from dirsrv: %s' % e self.log.exception(msg) raise CheckError(msg) except Exception as e: msg = ('Unknown error while retrieving setting from %s: %s' % (self.ldap_uri, e)) self.log.exception(msg) raise CheckError(msg) def _find_entry(self, dn, attrs, filter, scope=IPAdmin.SCOPE_BASE): """Find an LDAP entry, handles NotFound and Limit""" try: entries, truncated = self.con.find_entries( filter, attrs, dn, scope, time_limit=self.time_limit) if truncated: raise errors.LimitsExceeded() except errors.NotFound: self.log.debug('Entry not found: %s', dn) return None except Exception as e: msg = ('Unknown error while retrieving setting from %s: %s' % (self.ldap_uri, e)) self.log.exception(msg) raise CheckError(msg) return entries[0] def is_host_enabled(self): """Check replica specific flag""" self.log.debug('Read settings from dn: %s', self.kdc_dn) srcfilter = self.con.make_filter( {'ipaConfigString': u'kdcProxyEnabled'} ) entry = self._find_entry(self.kdc_dn, ['cn'], srcfilter) self.log.debug('%s ipaConfigString: %s', self.kdc_dn, entry) return entry is not None def validate_symlink(self): """Validate symlink in Apache conf.d""" if not os.path.exists(self.conflink): return False if not os.path.islink(self.conflink): raise CheckError("'%s' already exists, but it is not a symlink" % self.conflink) dest = os.readlink(self.conflink) if dest != self.conf: raise CheckError("'%s' points to '%s', expected '%s'" % (self.conflink, dest, self.conf)) return True def create_symlink(self): """Create symlink to enable KDC proxy support""" try: valid = self.validate_symlink() except CheckError as e: self.log.warn("Cannot enable KDC proxy: %s " % e) return False if valid: self.log.debug("Symlink exists and is valid") return True if not os.path.isfile(self.conf): self.log.warn("'%s' does not exist", self.conf) return False # create the symbolic link self.log.debug("Creating symlink from '%s' to '%s'", self.conf, self.conflink) os.symlink(self.conf, self.conflink) return True def remove_symlink(self): """Delete symlink to disable KDC proxy support""" try: valid = self.validate_symlink() except CheckError as e: self.log.warn("Cannot disable KDC proxy: %s " % e) return False if valid: self.log.debug("Removing symlink '%s'", self.conflink) os.unlink(self.conflink) else: self.log.debug("Symlink '%s' has already been removed.", self.conflink) return True def __enter__(self): self._ldap_con() return self def __exit__(self, exc_type, exc_value, traceback): if self.con is not None: self.con.unbind() self.con = None def main(debug=DEBUG, time_limit=TIME_LIMIT): # initialize API without file logging if not api.isdone('bootstrap'): api.bootstrap(context='kdcproxyshim', log=None, debug=debug) standard_logging_setup(verbose=True, debug=debug) with KDCProxyConfig(time_limit) as cfg: if cfg.is_host_enabled(): if cfg.create_symlink(): api.log.info('KDC proxy enabled') else: if cfg.remove_symlink(): api.log.info('KDC proxy disabled') if __name__ == '__main__': main()