From 21bf175e0c10b087deb10b8e328a6a6bd549c0f9 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 5 Jan 2011 07:46:30 -0500 Subject: Allow ipa-dns-install to install with just admin credentials Do this by creating a common way to attach to the ldap server for each instance. Fixes: https://fedorahosted.org/freeipa/ticket/686 --- install/tools/ipa-dns-install | 51 +++++++++++++++++++++--------------- install/tools/ipa-server-install | 1 - ipaserver/install/bindinstance.py | 17 +++--------- ipaserver/install/httpinstance.py | 4 +++ ipaserver/install/krbinstance.py | 43 ++++++++----------------------- ipaserver/install/service.py | 54 ++++++++++++++++++++++----------------- 6 files changed, 81 insertions(+), 89 deletions(-) diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install index 01967c179..25aeb610e 100755 --- a/install/tools/ipa-dns-install +++ b/install/tools/ipa-dns-install @@ -28,6 +28,8 @@ from ipapython import version from ipapython import ipautil, sysrestore from ipalib import api, errors, util from ipapython.config import IPAOptionParser +import krbV +import ldap def parse_options(): parser = IPAOptionParser(version=version.VERSION) @@ -52,8 +54,6 @@ def parse_options(): parser.error("You cannot specify a --forwarder option together with --no-forwarders") if options.unattended: - if not options.dm_password: - parser.error("In unattended mode you need to provide at least the -p option") if not options.forwarders and not options.no_forwarders: parser.error("You must specify at least one --forwarder option or --no-forwarders option") @@ -138,22 +138,6 @@ def main(): dns_forwarders = read_dns_forwarders() logging.debug("will use dns_forwarders: %s\n", str(dns_forwarders)) - if not options.dm_password: - dm_password = read_password("Directory Manager", confirm=False, validate=False) - else: - dm_password = options.dm_password - - # Try out the password - ldapuri = 'ldap://%s' % api.env.host - try: - conn = ldap2(shared_instance=False, ldap_uri=ldapuri) - conn.connect(bind_dn='cn=directory manager', bind_pw=dm_password) - conn.disconnect() - except errors.ACIError: - sys.exit("\nThe password provided is incorrect for LDAP server %s" % api.env.host) - except errors.LDAPError: - sys.exit("\nUnable to connect to LDAP server %s" % api.env.host) - conf_ntp = ntpinstance.NTPInstance(fstore).is_enabled() if not options.unattended: @@ -163,12 +147,39 @@ def main(): print "" # Create a BIND instance - bind = bindinstance.BindInstance(fstore, dm_password) + bind = bindinstance.BindInstance(fstore, options.dm_password) + + valid_password = False + while not valid_password: + # try the connection + try: + bind.ldap_connect() + bind.ldap_disconnect() + valid_password = True + except ldap.LOCAL_ERROR, e: + if not bind.dm_password: + if options.unattended: + sys.exit("\nIn unattended mode you need to provide at least the -p option") + else: + bind.dm_password = read_password("Directory Manager", confirm=False, validate=False) + except ldap.INVALID_CREDENTIALS, e: + if options.unattended: + sys.exit("\nPassword is not valid!") + bind.dm_password = read_password("Directory Manager", confirm=False, validate=False) + create_reverse = bindinstance.create_reverse(options.unattended) bind.setup(api.env.host, ip_address, api.env.realm, api.env.domain, dns_forwarders, conf_ntp, create_reverse, zonemgr=options.zonemgr) - api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=dm_password) + + if bind.dm_password: + api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=bind.dm_password) + else: + # See if our LDAP server is up and we can talk to it over GSSAPI + ccache = krbV.default_context().default_ccache().name + api.Backend.ldap2.connect(ccache) + bind.create_instance() + print "==============================================================================" print "Setup complete" print "" diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install index 2bbf48171..19f80a791 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install @@ -797,7 +797,6 @@ def main(): # generated ds.add_cert_to_service() - # Create a HTTP instance if options.http_pin: diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py index 4b52137bf..73deda096 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -217,7 +217,6 @@ class BindInstance(service.Service): service.Service.__init__(self, "named", dm_password=dm_password) self.dns_backup = DnsBackup(self) self.named_user = None - self.fqdn = None self.domain = None self.host = None self.ip_address = None @@ -270,6 +269,9 @@ class BindInstance(service.Service): except: pass + # get a connection to the DS + self.ldap_connect() + if not dns_container_exists(self.fqdn, self.suffix): self.step("adding DNS container", self.__setup_dns_container) if not dns_zone_exists(self.domain): @@ -384,30 +386,19 @@ class BindInstance(service.Service): # it can host the memberof attribute, then also add it to the # dnsserver role group, this way the DNS is allowed to perform # DNS Updates - conn = None - - try: - conn = ipaldap.IPAdmin("127.0.0.1") - conn.simple_bind_s("cn=directory manager", self.dm_password) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s" % self.fqdn) - raise e - dns_group = "cn=dnsserver,cn=privileges,cn=pbac,%s" % self.suffix if isinstance(dns_principal, unicode): dns_principal = dns_principal.encode('utf-8') mod = [(ldap.MOD_ADD, 'member', dns_principal)] try: - conn.modify_s(dns_group, mod) + self.admin_conn.modify_s(dns_group, mod) except ldap.TYPE_OR_VALUE_EXISTS: pass except Exception, e: logging.critical("Could not modify principal's %s entry" % dns_principal) raise e - conn.unbind() - def __setup_named_conf(self): self.fstore.backup_file('/etc/named.conf') named_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.named.conf.template", self.sub_dict) diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py index 776511fa0..46a5676f2 100644 --- a/ipaserver/install/httpinstance.py +++ b/ipaserver/install/httpinstance.py @@ -68,6 +68,10 @@ class HTTPInstance(service.Service): self.subject_base = subject_base self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain } + # get a connection to the DS + self.ldap_connect() + + self.step("disabling mod_ssl in httpd", self.__disable_mod_ssl) self.step("Setting mod_nss port to 443", self.__set_mod_nss_port) self.step("Setting mod_nss password file", self.__set_mod_nss_passwordfile) diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py index 3f524d741..4ad2fcec9 100644 --- a/ipaserver/install/krbinstance.py +++ b/ipaserver/install/krbinstance.py @@ -99,17 +99,10 @@ class KrbInstance(service.Service): Used to move a host/ service principal created by kadmin.local from cn=kerberos to reside under the host entry. """ - conn = None service_dn = "krbprincipalname=%s,cn=%s,cn=kerberos,%s" % (principal, self.realm, self.suffix) - try: - conn = ipaldap.IPAdmin("127.0.0.1") - conn.simple_bind_s("cn=directory manager", self.admin_password) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s" % self.fqdn) - raise e - service_entry = conn.getEntry(service_dn, ldap.SCOPE_BASE) - conn.deleteEntry(service_dn) + service_entry = self.admin_conn.getEntry(service_dn, ldap.SCOPE_BASE) + self.admin_conn.deleteEntry(service_dn) # Create a host entry for this master host_dn = "fqdn=%s,cn=computers,cn=accounts,%s" % (self.fqdn, self.suffix) @@ -127,8 +120,7 @@ class KrbInstance(service.Service): host_entry.setValue('fqdn', self.fqdn) host_entry.setValue('ipauniqueid', 'autogenerate') host_entry.setValue('managedby', host_dn) - conn.addEntry(host_entry) - conn.unbind() + self.admin_conn.addEntry(host_entry) def __common_setup(self, ds_user, realm_name, host_name, domain_name, admin_password): self.ds_user = ds_user @@ -145,12 +137,7 @@ class KrbInstance(service.Service): self.__setup_sub_dict() # get a connection to the DS - try: - self.conn = ipaldap.IPAdmin(self.fqdn) - self.conn.do_simple_bind(bindpw=self.admin_password) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s" % self.fqdn) - raise e + self.ldap_connect() self.backup_state("running", self.is_running()) try: @@ -271,12 +258,12 @@ class KrbInstance(service.Service): # they may conflict. try: - res = self.conn.search_s("cn=mapping,cn=sasl,cn=config", + res = self.admin_conn.search_s("cn=mapping,cn=sasl,cn=config", ldap.SCOPE_ONELEVEL, "(objectclass=nsSaslMapping)") for r in res: try: - self.conn.delete_s(r.dn) + self.admin_conn.delete_s(r.dn) except LDAPError, e: logging.critical("Error during SASL mapping removal: %s" % str(e)) raise e @@ -292,7 +279,7 @@ class KrbInstance(service.Service): entry.setValues("nsSaslMapFilterTemplate", '(krbPrincipalName=\\1@\\2)') try: - self.conn.add_s(entry) + self.admin_conn.add_s(entry) except ldap.ALREADY_EXISTS: logging.critical("failed to add Full Principal Sasl mapping") raise e @@ -305,7 +292,7 @@ class KrbInstance(service.Service): entry.setValues("nsSaslMapFilterTemplate", '(krbPrincipalName=&@%s)' % self.realm) try: - self.conn.add_s(entry) + self.admin_conn.add_s(entry) except ldap.ALREADY_EXISTS: logging.critical("failed to add Name Only Sasl mapping") raise e @@ -383,7 +370,7 @@ class KrbInstance(service.Service): def __write_stash_from_ds(self): try: - entry = self.conn.getEntry("cn=%s, cn=kerberos, %s" % (self.realm, self.suffix), ldap.SCOPE_SUBTREE) + entry = self.admin_conn.getEntry("cn=%s, cn=kerberos, %s" % (self.realm, self.suffix), ldap.SCOPE_SUBTREE) except errors.NotFound, e: logging.critical("Could not find master key in DS") raise e @@ -485,7 +472,7 @@ class KrbInstance(service.Service): mod = [(ldap.MOD_ADD, 'aci', ipautil.template_str(KRBMKEY_DENY_ACI, self.sub_dict)), (ldap.MOD_ADD, 'krbMKey', str(asn1key))] try: - self.conn.modify_s(dn, mod) + self.admin_conn.modify_s(dn, mod) except ldap.TYPE_OR_VALUE_EXISTS, e: logging.critical("failed to add master key to kerberos database\n") raise e @@ -553,16 +540,8 @@ class KrbInstance(service.Service): # Create the special anonymous principal installutils.kadmin_addprinc(princ_realm) - try: - conn = ipaldap.IPAdmin("127.0.0.1") - conn.simple_bind_s("cn=directory manager", self.admin_password) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s" % self.fqdn) - raise e - dn = "krbprincipalname=%s,cn=%s,cn=kerberos,%s" % (princ_realm, self.realm, self.suffix) - conn.inactivateEntry(dn, False) - conn.unbind() + self.admin_conn.inactivateEntry(dn, False) def uninstall(self): if self.is_configured(): diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py index b8d049fee..6fcac24ce 100644 --- a/ipaserver/install/service.py +++ b/ipaserver/install/service.py @@ -18,7 +18,7 @@ # import logging, sys -import os +import os, socket import tempfile from ipapython import sysrestore from ipapython import ipautil @@ -30,6 +30,9 @@ import time import datetime from ipaserver.install import installutils +CACERT = "/etc/ipa/ca.crt" +SASL_AUTH = ldap.sasl.sasl({}, 'GSSAPI') + SERVICE_LIST = { 'KDC':('krb5kdc', 10), 'KPASSWD':('ipa_kpasswd', 20), @@ -100,11 +103,21 @@ class Service: self.output_fd = sys.stdout self.dm_password = dm_password + self.fqdn = socket.gethostname() + self.admin_conn = None + if sstore: self.sstore = sstore else: self.sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') + def ldap_connect(self): + self.admin_conn = self.__get_conn(self.fqdn, self.dm_password) + + def ldap_disconnect(self): + self.admin_conn.unbind() + self.admin_conn = None + def _ldap_mod(self, ldif, sub_dict = None): pw_name = None @@ -145,31 +158,24 @@ class Service: Used to move a principal entry created by kadmin.local from cn=kerberos to cn=services """ + dn = "krbprincipalname=%s,cn=%s,cn=kerberos,%s" % (principal, self.realm, self.suffix) try: - conn = ipaldap.IPAdmin("127.0.0.1") - conn.simple_bind_s("cn=directory manager", self.dm_password) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s: %s" % (self.fqdn, str(e))) - raise e - try: - entry = conn.getEntry(dn, ldap.SCOPE_BASE) + entry = self.admin_conn.getEntry(dn, ldap.SCOPE_BASE) except errors.NotFound: # There is no service in the wrong location, nothing to do. # This can happen when installing a replica - conn.unbind() return newdn = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (principal, self.suffix) hostdn = "fqdn=%s,cn=computers,cn=accounts,%s" % (self.fqdn, self.suffix) - conn.deleteEntry(dn) + self.admin_conn.deleteEntry(dn) entry.dn = newdn classes = entry.getValues("objectclass") classes = classes + ["ipaobject", "ipaservice", "pkiuser"] entry.setValues("objectclass", list(set(classes))) entry.setValue("ipauniqueid", 'autogenerate') entry.setValue("managedby", hostdn) - conn.addEntry(entry) - conn.unbind() + self.admin_conn.addEntry(entry) return newdn def add_cert_to_service(self): @@ -180,6 +186,10 @@ class Service: a base64-encoded cert if needed (like when we add certs that come from PKCS#12 files.) """ + + if not self.admin_conn: + self.ldap_connect() + try: s = self.dercert.find('-----BEGIN CERTIFICATE-----') if s > -1: @@ -190,18 +200,11 @@ class Service: except Exception: pass dn = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (self.principal, self.suffix) - try: - conn = ipaldap.IPAdmin("127.0.0.1") - conn.simple_bind_s("cn=directory manager", self.dm_password) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s: %s" % (self.fqdn, str(e))) - raise e mod = [(ldap.MOD_ADD, 'userCertificate', self.dercert)] try: - conn.modify_s(dn, mod) + self.admin_conn.modify_s(dn, mod) except Exception, e: logging.critical("Could not add certificate to service %s entry: %s" % (self.principal, str(e))) - conn.unbind() def is_configured(self): return self.sstore.has_state(self.service_name) @@ -278,11 +281,16 @@ class Service: self.steps = [] def __get_conn(self, fqdn, dm_password): + # 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("127.0.0.1") - conn.simple_bind_s("cn=directory manager", dm_password) + conn = ipaldap.IPAdmin(fqdn, port=636, cacert=CACERT) + if dm_password: + conn.do_simple_bind(bindpw=dm_password) + else: + conn.sasl_interactive_bind_s('', SASL_AUTH) except Exception, e: - logging.critical("Could not connect to the Directory Server on %s: %s" % (fqdn, str(e))) + logging.debug("Could not connect to the Directory Server on %s: %s" % (fqdn, str(e))) raise e return conn -- cgit