mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-27 09:21:59 -06:00
1f0959735f
When LDAP search fails on exceeded limits, we should raise an specific exception for the type of limit raised (size, time, administrative) so that the consumer can distinguish between e.g. searches returning too many entries and those timing out. https://fedorahosted.org/freeipa/ticket/5677 Reviewed-By: Petr Spacek <pspacek@redhat.com>
215 lines
6.8 KiB
Python
Executable File
215 lines
6.8 KiB
Python
Executable File
#!/usr/bin/python2
|
|
# Authors:
|
|
# Christian Heimes <cheimes@redhat.com>
|
|
#
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
#
|
|
"""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 socket
|
|
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 Error(Exception):
|
|
"""Base error class"""
|
|
|
|
|
|
class ConfigFileError(Error):
|
|
"""Something is wrong with the config file"""
|
|
|
|
|
|
class CheckError(Error):
|
|
"""An unrecoverable error has occured
|
|
|
|
The exit code is 0.
|
|
"""
|
|
|
|
|
|
class FatalError(Error):
|
|
"""A fatal error has occured
|
|
|
|
Fatal errors cause the command to exit with a non-null exit code.
|
|
"""
|
|
|
|
|
|
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, socket.timeout) as e:
|
|
msg = 'Unable to connect to dirsrv: %s' % e
|
|
raise CheckError(msg)
|
|
except errors.AuthorizationError as e:
|
|
msg = 'Authorization error: %s' % e
|
|
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 FatalError(msg)
|
|
|
|
def _find_entry(self, dn, attrs, filter, scope=IPAdmin.SCOPE_BASE):
|
|
"""Find an LDAP entry, handles NotFound and Limit"""
|
|
try:
|
|
entries = self.con.get_entries(
|
|
dn, scope, filter, attrs, time_limit=self.time_limit)
|
|
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 FatalError(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 ConfigFileError(
|
|
"'%s' already exists, but it is not a symlink"
|
|
% self.conflink)
|
|
dest = os.readlink(self.conflink)
|
|
if dest != self.conf:
|
|
raise ConfigFileError(
|
|
"'%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 ConfigFileError as e:
|
|
self.log.warning("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.warning("'%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.warning("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='ipa-httpd-kdcproxy', log=None, debug=debug)
|
|
standard_logging_setup(verbose=True, debug=debug)
|
|
|
|
try:
|
|
cfg = KDCProxyConfig(time_limit)
|
|
with cfg:
|
|
if cfg.is_host_enabled():
|
|
if cfg.create_symlink():
|
|
api.log.info('KDC proxy enabled')
|
|
return 0
|
|
else:
|
|
if cfg.remove_symlink():
|
|
api.log.info('KDC proxy disabled')
|
|
return 0
|
|
except CheckError as e:
|
|
api.log.warning(str(e))
|
|
api.log.warning('Disabling KDC proxy')
|
|
cfg.remove_symlink()
|
|
return 0
|
|
except Exception as e:
|
|
api.log.error(str(e))
|
|
return 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|