summaryrefslogtreecommitdiffstats
path: root/ipaserver
diff options
context:
space:
mode:
authorAlexander Bokovoy <abokovoy@redhat.com>2012-07-13 18:12:48 +0300
committerMartin Kosek <mkosek@redhat.com>2012-07-31 17:44:35 +0200
commit68d5fe1ec7d785f127b3513f84cc632cdb1f9167 (patch)
treec0723e680c929f19f4fd2cb61eb7dfd93287d267 /ipaserver
parent16ca564b1004eb672fe4ca3573e542f5a3ce014b (diff)
downloadfreeipa-68d5fe1ec7d785f127b3513f84cc632cdb1f9167.tar.gz
freeipa-68d5fe1ec7d785f127b3513f84cc632cdb1f9167.tar.xz
freeipa-68d5fe1ec7d785f127b3513f84cc632cdb1f9167.zip
Ensure ipa-adtrust-install is run with Kerberos ticket for admin user
When setting up AD trusts support, ipa-adtrust-install utility needs to be run as: - root, for performing Samba configuration and using LDAPI/autobind - kinit-ed IPA admin user, to ensure proper ACIs are granted to fetch keytab As result, we can get rid of Directory Manager credentials in ipa-adtrust-install https://fedorahosted.org/freeipa/ticket/2815
Diffstat (limited to 'ipaserver')
-rw-r--r--ipaserver/install/adtrustinstance.py21
-rw-r--r--ipaserver/install/bindinstance.py2
-rw-r--r--ipaserver/install/cainstance.py3
-rw-r--r--ipaserver/install/dsinstance.py2
-rw-r--r--ipaserver/install/krbinstance.py2
-rw-r--r--ipaserver/install/service.py114
6 files changed, 89 insertions, 55 deletions
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index 20feec4df..9dcbec2d6 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -96,10 +96,9 @@ class ADTRUSTInstance(service.Service):
OBJC_GROUP = "ipaNTGroupAttrs"
OBJC_DOMAIN = "ipaNTDomainAttrs"
- def __init__(self, fstore=None, dm_password=None):
+ def __init__(self, fstore=None):
self.fqdn = None
self.ip_address = None
- self.realm_name = None
self.domain_name = None
self.netbios_name = None
self.no_msdcs = None
@@ -118,7 +117,7 @@ class ADTRUSTInstance(service.Service):
self.rid_base = None
self.secondary_rid_base = None
- service.Service.__init__(self, "smb", dm_password=dm_password)
+ service.Service.__init__(self, "smb", dm_password=None, ldapi=True)
if fstore:
self.fstore = fstore
@@ -436,6 +435,8 @@ class ADTRUSTInstance(service.Service):
# We do not let the system start IPA components on its own,
# Instead we reply on the IPA init script to start only enabled
# components as found in our LDAP configuration tree
+ # Note that self.dm_password is None for ADTrustInstance because
+ # we ensure to be called as root and using ldapi to use autobind
try:
self.ldap_enable('ADTRUST', self.fqdn, self.dm_password, \
self.suffix)
@@ -449,7 +450,7 @@ class ADTRUSTInstance(service.Service):
root_logger.info("EXTID Service startup entry already exists.")
def __setup_sub_dict(self):
- self.sub_dict = dict(REALM = self.realm_name,
+ self.sub_dict = dict(REALM = self.realm,
SUFFIX = self.suffix,
NETBIOS_NAME = self.netbios_name,
SMB_DN = self.smb_dn,
@@ -460,16 +461,16 @@ class ADTRUSTInstance(service.Service):
rid_base, secondary_rid_base, no_msdcs=False, smbd_user="samba"):
self.fqdn = fqdn
self.ip_address = ip_address
- self.realm_name = realm_name
+ self.realm = realm_name
self.domain_name = domain_name
self.netbios_name = netbios_name
self.rid_base = rid_base
self.secondary_rid_base = secondary_rid_base
self.no_msdcs = no_msdcs
self.smbd_user = smbd_user
- self.suffix = ipautil.realm_to_suffix(self.realm_name)
+ self.suffix = ipautil.realm_to_suffix(self.realm)
self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \
- realm_to_serverid(self.realm_name)
+ realm_to_serverid(self.realm)
self.smb_conf = "/etc/samba/smb.conf"
@@ -479,7 +480,7 @@ class ADTRUSTInstance(service.Service):
self.trust_dn = str(DN(api.env.container_trusts, self.suffix))
self.smb_dom_dn = str(DN(('cn', self.domain_name),
api.env.container_cifsdomains, self.suffix))
- self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm_name
+ self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm
self.cifs_agent = str(DN(('krbprincipalname', self.cifs_principal.lower()),
api.env.container_service,
self.suffix))
@@ -522,11 +523,11 @@ class ADTRUSTInstance(service.Service):
"range.\nAdd local ID range manually and try " \
"again!")
- entry = ipaldap.Entry(str(DN(('cn', ('%s_id_range' % self.realm_name)),
+ entry = ipaldap.Entry(str(DN(('cn', ('%s_id_range' % self.realm)),
api.env.container_ranges,
self.suffix)))
entry.setValue('objectclass', 'ipaDomainIDRange')
- entry.setValue('cn', ('%s_id_range' % self.realm_name))
+ entry.setValue('cn', ('%s_id_range' % self.realm))
entry.setValue('ipaBaseID', str(base_id))
entry.setValue('ipaIDRangeSize', str(id_range_size))
self.admin_conn.addEntry(entry)
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index c348cdbb2..f320202ea 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -448,7 +448,7 @@ class DnsBackup(object):
class BindInstance(service.Service):
def __init__(self, fstore=None, dm_password=None):
- service.Service.__init__(self, "named", dm_password=dm_password)
+ service.Service.__init__(self, "named", dm_password=dm_password, ldapi=False, autobind=service.DISABLED)
self.dns_backup = DnsBackup(self)
self.named_user = None
self.domain = None
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 2644689a0..dc4374cce 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -225,10 +225,9 @@ def get_outputList(data):
class CADSInstance(service.Service):
def __init__(self, host_name=None, realm_name=None, domain_name=None, dm_password=None):
- service.Service.__init__(self, "pkids")
+ service.Service.__init__(self, "pkids", dm_password=dm_password, ldapi=False, autobind=service.DISABLED)
self.serverid = "PKI-IPA"
self.realm_name = realm_name
- self.dm_password = dm_password
self.sub_dict = None
self.domain = domain_name
self.fqdn = host_name
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 25c449a6e..9f3ae7252 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -160,7 +160,7 @@ info: IPA V2.0
class DsInstance(service.Service):
def __init__(self, realm_name=None, domain_name=None, dm_password=None, fstore=None):
- service.Service.__init__(self, "dirsrv", dm_password=dm_password)
+ service.Service.__init__(self, "dirsrv", dm_password=dm_password, ldapi=False, autobind=service.DISABLED)
self.realm_name = realm_name
self.sub_dict = None
self.domain = domain_name
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 2faf8e196..8cc50fba4 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -178,7 +178,7 @@ class KrbInstance(service.Service):
self.start_creation("Configuring Kerberos KDC", 30)
self.kpasswd = KpasswdInstance()
- self.kpasswd.create_instance('KPASSWD', self.fqdn, self.admin_password, self.suffix)
+ self.kpasswd.create_instance('KPASSWD', self.fqdn, self.admin_password, self.suffix, realm=self.realm)
def create_replica(self, realm_name,
master_fqdn, host_name,
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 5c2699e3f..198cb3870 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -35,6 +35,11 @@ from ipapython.ipa_log_manager import *
CACERT = "/etc/ipa/ca.crt"
+# Autobind modes
+AUTO = 1
+ENABLED = 2
+DISABLED = 3
+
# The service name as stored in cn=masters,cn=ipa,cn=etc. In the tuple
# the first value is the *nix service name, the second the start order.
SERVICE_LIST = {
@@ -55,13 +60,14 @@ def print_msg(message, output_fd=sys.stdout):
class Service(object):
- def __init__(self, service_name, sstore=None, dm_password=None, ldapi=False):
+ def __init__(self, service_name, sstore=None, dm_password=None, ldapi=True, autobind=AUTO):
self.service_name = service_name
self.service = ipaservices.service(service_name)
self.steps = []
self.output_fd = sys.stdout
self.dm_password = dm_password
self.ldapi = ldapi
+ self.autobind = autobind
self.fqdn = socket.gethostname()
self.admin_conn = None
@@ -77,12 +83,44 @@ class Service(object):
self.dercert = None
def ldap_connect(self):
- if self.ldapi:
- if not self.realm:
- raise RuntimeError('realm must be set to use ldapi connection')
- self.admin_conn = self.__get_conn(None, None, ldapi=True, realm=self.realm)
- else:
- self.admin_conn = self.__get_conn(self.fqdn, self.dm_password)
+ # If DM password is provided, we use it
+ # If autobind was requested, attempt autobind when root and ldapi
+ # If autobind was disabled or not succeeded, go with GSSAPI
+ # LDAPI can be used with either autobind or GSSAPI
+ # LDAPI requires realm to be set
+ try:
+ if self.ldapi:
+ if not self.realm:
+ raise errors.NotFound(reason="realm is missing for %s" % (self))
+ conn = ipaldap.IPAdmin(ldapi=self.ldapi, realm=self.realm)
+ else:
+ conn = ipaldap.IPAdmin(self.fqdn, port=389)
+ if self.dm_password:
+ conn.do_simple_bind(bindpw=self.dm_password)
+ elif self.autobind in [AUTO, ENABLED]:
+ if os.getegid() == 0 and self.ldapi:
+ try:
+ # autobind
+ pw_name = pwd.getpwuid(os.geteuid()).pw_name
+ conn.do_external_bind(pw_name)
+ except errors.NotFound, e:
+ if self.autobind == AUTO:
+ # Fall back
+ conn.do_sasl_gssapi_bind()
+ else:
+ # autobind was required and failed, raise
+ # exception that it failed
+ raise e
+ else:
+ conn.do_sasl_gssapi_bind()
+ else:
+ conn.do_sasl_gssapi_bind()
+ except Exception, e:
+ root_logger.debug("Could not connect to the Directory Server on %s: %s" % (self.fqdn, str(e)))
+ raise e
+
+ self.admin_conn = conn
+
def ldap_disconnect(self):
self.admin_conn.unbind()
@@ -93,7 +131,6 @@ class Service(object):
pw_name = None
fd = None
path = ipautil.SHARE_DIR + ldif
- hostname = installutils.get_fqdn()
nologlist=[]
if sub_dict is not None:
@@ -107,15 +144,25 @@ class Service(object):
if sub_dict.has_key('RANDOM_PASSWORD'):
nologlist.append(sub_dict['RANDOM_PASSWORD'])
+ args = ["/usr/bin/ldapmodify", "-v", "-f", path]
+
+ # As we always connect to the local host,
+ # use URI of admin connection
+ if not self.admin_conn:
+ self.ldap_connect()
+ args += ["-H", self.admin_conn._uri]
+
+ auth_parms = []
if self.dm_password:
[pw_fd, pw_name] = tempfile.mkstemp()
os.write(pw_fd, self.dm_password)
os.close(pw_fd)
auth_parms = ["-x", "-D", "cn=Directory Manager", "-y", pw_name]
else:
- auth_parms = ["-Y", "GSSAPI"]
+ # always try GSSAPI auth when not using DM password or not being root
+ if os.getegid() != 0:
+ auth_parms = ["-Y", "GSSAPI"]
- args = ["/usr/bin/ldapmodify", "-h", hostname, "-v", "-f", path]
args += auth_parms
try:
@@ -181,8 +228,19 @@ class Service(object):
This server cert should be in DER format.
"""
- if not self.admin_conn:
- self.ldap_connect()
+ # add_cert_to_service() is relatively rare operation
+ # we actually call it twice during ipa-server-install, for different
+ # instances: ds and cs. Unfortunately, it may happen that admin
+ # connection was created well before add_cert_to_service() is called
+ # If there are other operations in between, it will become stale and
+ # since we are using SimpleLDAPObject, not ReconnectLDAPObject, the
+ # action will fail. Thus, explicitly disconnect and connect again.
+ # Using ReconnectLDAPObject instead of SimpleLDAPObject was considered
+ # but consequences for other parts of the framework are largely
+ # unknown.
+ if self.admin_conn:
+ self.ldap_disconnect()
+ self.ldap_connect()
dn = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (self.principal, self.suffix)
mod = [(ldap.MOD_ADD, 'userCertificate', self.dercert)]
@@ -268,33 +326,6 @@ class Service(object):
self.steps = []
- def __get_conn(self, fqdn, dm_password, ldapi=False, realm=None):
- # If we are passed a password we'll use it as the DM password
- # otherwise we'll do a GSSAPI bind.
- try:
-# conn = ipaldap.IPAdmin(fqdn, port=636, cacert=CACERT)
- if ldapi:
- conn = ipaldap.IPAdmin(ldapi=ldapi, realm=realm)
- else:
- conn = ipaldap.IPAdmin(fqdn, port=389)
- if dm_password:
- conn.do_simple_bind(bindpw=dm_password)
- elif os.getegid() == 0 and self.ldapi:
- try:
- # autobind
- pw_name = pwd.getpwuid(os.geteuid()).pw_name
- conn.do_external_bind(pw_name)
- except errors.NotFound:
- # Fall back
- conn.do_sasl_gssapi_bind()
- else:
- conn.do_sasl_gssapi_bind()
- except Exception, e:
- root_logger.debug("Could not connect to the Directory Server on %s: %s" % (fqdn, str(e)))
- raise e
-
- return conn
-
def ldap_enable(self, name, fqdn, dm_password, ldap_suffix):
self.disable()
if not self.admin_conn:
@@ -318,11 +349,14 @@ class Service(object):
raise e
class SimpleServiceInstance(Service):
- def create_instance(self, gensvc_name=None, fqdn=None, dm_password=None, ldap_suffix=None):
+ def create_instance(self, gensvc_name=None, fqdn=None, dm_password=None, ldap_suffix=None, realm=None):
self.gensvc_name = gensvc_name
self.fqdn = fqdn
self.dm_password = dm_password
self.suffix = ldap_suffix
+ self.realm = realm
+ if not realm:
+ self.ldapi = False
self.step("starting %s " % self.service_name, self.__start)
self.step("configuring %s to start on boot" % self.service_name, self.__enable)