summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xipa-client/ipa-install/ipa-client-install80
-rw-r--r--ipa-client/ipaclient/ipadiscovery.py135
2 files changed, 150 insertions, 65 deletions
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 8dfe1db68..9a8600d55 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -1112,18 +1112,21 @@ def install(options, env, fstore, statestore):
cli_domain = None
cli_server = None
- cli_realm = None
- cli_basedn = None
subject_base = None
+ cli_domain_source = 'Unknown source'
+ cli_server_source = 'Unknown source'
+
if options.unattended and (options.password is None and options.principal is None and options.prompt_password is False) and not options.on_master:
root_logger.error("One of password and principal are required.")
return CLIENT_INSTALL_ERROR
if options.hostname:
hostname = options.hostname
+ hostname_source = 'Provided as option'
else:
hostname = socket.getfqdn()
+ hostname_source = "Machine's FQDN"
if hostname != hostname.lower():
root_logger.error(
"Invalid hostname '%s', must be lower-case.", hostname)
@@ -1153,10 +1156,22 @@ def install(options, env, fstore, statestore):
root_logger.error("%s is not a fully-qualified hostname", hostname)
return CLIENT_INSTALL_ERROR
if ret in (ipadiscovery.NO_LDAP_SERVER, ipadiscovery.NOT_IPA_SERVER) \
- or not ds.getDomainName():
- root_logger.debug("Domain not found")
+ or not ds.domain:
+ if ret == ipadiscovery.NO_LDAP_SERVER:
+ if ds.server:
+ root_logger.debug("%s is not an LDAP server" % ds.server)
+ else:
+ root_logger.debug("No LDAP server found")
+ elif ret == ipadiscovery.NOT_IPA_SERVER:
+ if ds.server:
+ root_logger.debug("%s is not an IPA server" % ds.server)
+ else:
+ root_logger.debug("No IPA server found")
+ else:
+ root_logger.debug("Domain not found")
if options.domain:
cli_domain = options.domain
+ cli_domain_source = 'Provided as option'
elif options.unattended:
root_logger.error(
"Unable to discover domain, not provided on command line")
@@ -1165,38 +1180,45 @@ def install(options, env, fstore, statestore):
root_logger.info(
"DNS discovery failed to determine your DNS domain")
cli_domain = user_input("Provide the domain name of your IPA server (ex: example.com)", allow_empty = False)
- root_logger.debug("will use domain: %s", cli_domain)
+ cli_domain_source = 'Provided interactively'
+ root_logger.debug(
+ "will use interactively provided domain: %s", cli_domain)
ret = ds.search(domain=cli_domain, server=options.server, hostname=hostname)
if not cli_domain:
- if ds.getDomainName():
- cli_domain = ds.getDomainName()
- root_logger.debug("will use domain: %s", cli_domain)
+ if ds.domain:
+ cli_domain = ds.domain
+ cli_domain_source = ds.domain_source
+ root_logger.debug("will use discovered domain: %s", cli_domain)
client_domain = hostname[hostname.find(".")+1:]
if ret in (ipadiscovery.NO_LDAP_SERVER, ipadiscovery.NOT_IPA_SERVER) \
- or not ds.getServerName():
+ or not ds.server:
root_logger.debug("IPA Server not found")
if options.server:
cli_server = options.server
+ cli_server_source = 'Provided as option'
elif options.unattended:
root_logger.error("Unable to find IPA Server to join")
return CLIENT_INSTALL_ERROR
else:
root_logger.debug("DNS discovery failed to find the IPA Server")
cli_server = user_input("Provide your IPA server name (ex: ipa.example.com)", allow_empty = False)
- root_logger.debug("will use server: %s", cli_server)
+ cli_server_source = 'Provided interactively'
+ root_logger.debug("will use interactively provided server: %s", cli_server)
ret = ds.search(domain=cli_domain, server=cli_server, hostname=hostname)
else:
dnsok = True
if not cli_server:
- if ds.getServerName():
- cli_server = ds.getServerName()
- root_logger.debug("will use server: %s", cli_server)
+ if ds.server:
+ cli_server = ds.server
+ cli_server_source = ds.server_source
+ root_logger.debug("will use discovered server: %s", cli_server)
if ret == ipadiscovery.NOT_IPA_SERVER:
root_logger.error("%s is not an IPA v2 Server.", cli_server)
+ root_logger.debug("(%s: %s)", cli_server, cli_server_source)
return CLIENT_INSTALL_ERROR
if ret == ipadiscovery.NO_ACCESS_TO_LDAP:
@@ -1211,12 +1233,14 @@ def install(options, env, fstore, statestore):
cli_server)
root_logger.error("This may mean that the remote server is not up " +
"or is not reachable due to network or firewall settings.")
+ root_logger.debug("(%s: %s)", cli_server, cli_server_source)
return CLIENT_INSTALL_ERROR
- cli_kdc = ds.getKDCName()
+ cli_kdc = ds.kdc
if dnsok and not cli_kdc:
root_logger.error("DNS domain '%s' is not configured for automatic " +
- "KDC address lookup.", ds.getRealmName().lower())
+ "KDC address lookup.", ds.realm.lower())
+ root_logger.debug("(%s: %s)", ds.realm, ds.realm_source)
root_logger.error("KDC address will be set to fixed value.")
if dnsok:
@@ -1233,23 +1257,32 @@ def install(options, env, fstore, statestore):
if not user_input("Proceed with fixed values and no DNS discovery?", False):
return CLIENT_INSTALL_ERROR
- if options.realm_name and options.realm_name != ds.getRealmName():
+ cli_realm = ds.realm
+ cli_realm_source = ds.realm_source
+ root_logger.debug("will use discovered realm: %s", cli_realm)
+
+ if options.realm_name and options.realm_name != cli_realm:
root_logger.error(
"The provided realm name [%s] does not match discovered one [%s]",
- options.realm_name, ds.getRealmName())
+ options.realm_name, cli_realm)
+ root_logger.debug("(%s: %s)", cli_realm, cli_realm_source)
return CLIENT_INSTALL_ERROR
- cli_realm = ds.getRealmName()
- root_logger.info("Will use cli_realm: %s", cli_realm)
- cli_basedn = ds.getBaseDN()
- root_logger.info("will use cli_basedn: %s", cli_basedn)
- subject_base = "O=%s" % ds.getRealmName()
+ cli_basedn = ds.basedn
+ cli_basedn_source = ds.basedn_source
+ root_logger.debug("will use discovered basedn: %s", cli_basedn)
+ subject_base = "O=%s" % cli_realm
root_logger.info("Hostname: %s", hostname)
+ root_logger.debug("Hostname source: %s", hostname_source)
root_logger.info("Realm: %s", cli_realm)
+ root_logger.debug("Realm source: %s", cli_realm_source)
root_logger.info("DNS Domain: %s", cli_domain)
+ root_logger.debug("DNS Domain source: %s", cli_domain_source)
root_logger.info("IPA Server: %s", cli_server)
+ root_logger.debug("IPA Server source: %s", cli_server_source)
root_logger.info("BaseDN: %s", cli_basedn)
+ root_logger.debug("BaseDN source: %s", cli_basedn_source)
print
if not options.unattended and not user_input("Continue to configure the system with these values?", False):
@@ -1279,7 +1312,8 @@ def install(options, env, fstore, statestore):
if not options.unattended:
if options.principal is None and options.password is None and options.prompt_password is False:
options.principal = user_input("User authorized to enroll computers", allow_empty=False)
- root_logger.debug("will use principal: %s\n", options.principal)
+ root_logger.debug(
+ "will use principal provided as option: %s", options.principal)
# Get the CA certificate
try:
diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py
index 281daf42a..f8c8b5c6d 100644
--- a/ipa-client/ipaclient/ipadiscovery.py
+++ b/ipa-client/ipaclient/ipadiscovery.py
@@ -38,7 +38,18 @@ NO_ACCESS_TO_LDAP = -5
BAD_HOST_CONFIG = -10
UNKNOWN_ERROR = -15
-class IPADiscovery:
+error_names = {
+ 0: 'Success',
+ NOT_FQDN: 'NOT_FQDN',
+ NO_LDAP_SERVER: 'NO_LDAP_SERVER',
+ REALM_NOT_FOUND: 'REALM_NOT_FOUND',
+ NOT_IPA_SERVER: 'NOT_IPA_SERVER',
+ NO_ACCESS_TO_LDAP: 'NO_ACCESS_TO_LDAP',
+ BAD_HOST_CONFIG: 'BAD_HOST_CONFIG',
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
+}
+
+class IPADiscovery(object):
def __init__(self):
self.realm = None
@@ -46,12 +57,18 @@ class IPADiscovery:
self.server = None
self.basedn = None
+ self.realm_source = None
+ self.domain_source = None
+ self.server_source = None
+ self.basedn_source = None
+
def __get_resolver_domains(self):
"""
Read /etc/resolv.conf and return all the domains found in domain and
search.
- Returns a list
+ Returns a list of (domain, info) pairs. The info contains a reason why
+ the domain is returned.
"""
domains = []
domain = None
@@ -62,12 +79,14 @@ class IPADiscovery:
for line in lines:
if line.lower().startswith('domain'):
- domain = line.split(None)[-1]
+ domain = (line.split()[-1],
+ 'local domain from /etc/resolv.conf')
elif line.lower().startswith('search'):
- domains = domains + line.split(None)[1:]
+ domains += [(d, 'search domain from /etc/resolv.conf') for
+ d in line.split()[1:]]
except:
pass
- if domain and not domain in domains:
+ if domain:
domains = [domain] + domains
return domains
@@ -86,18 +105,26 @@ class IPADiscovery:
def getBaseDN(self):
return self.basedn
- def check_domain(self, domain):
+ def check_domain(self, domain, tried, reason):
"""
Given a domain search it for SRV records, breaking it down to search
all subdomains too.
Returns a tuple (server, domain) or (None,None) if a SRV record
isn't found.
+
+ :param tried: A set of domains that were tried already
+ :param reason: Reason this domain is searched (included in the log)
"""
server = None
- root_logger.debug("Start searching for LDAP SRV record in %s and"
- " its sub-domains", domain)
+ root_logger.debug('Start searching for LDAP SRV record in "%s" (%s) ' +
+ 'and its sub-domains', domain, reason)
while not server:
+ if domain in tried:
+ root_logger.debug("Already searched %s; skipping", domain)
+ break
+ tried.add(domain)
+
server = self.ipadns_search_srv(domain, '_ldap._tcp', 389)
if server:
return (server[0], domain)
@@ -109,11 +136,10 @@ class IPADiscovery:
return (None, None)
def search(self, domain = "", server = "", hostname=None):
- qname = ""
- results = []
- result = []
- krbret = []
- ldapret = []
+ root_logger.debug("[IPA Discovery]")
+ root_logger.debug(
+ 'Starting IPA discovery with domain=%s, server=%s, hostname=%s',
+ domain, server, hostname)
if not server:
@@ -122,6 +148,7 @@ class IPADiscovery:
# get the local host name
if not hostname:
hostname = socket.getfqdn()
+ root_logger.debug('Hostname: %s', hostname)
if not hostname:
return BAD_HOST_CONFIG
@@ -135,20 +162,24 @@ class IPADiscovery:
domain = hostname[p+1:]
# Get the list of domains from /etc/resolv.conf, we'll search
- # them all. We search the domain of our hostname first though,
- # even if that means searching it twice. This is to avoid the
- # situation where domain isn't set in /etc/resolv.conf and
- # the search list has the hostname domain not first. We could
- # end up with the wrong SRV record.
+ # them all. We search the domain of our hostname first though.
+ # This is to avoid the situation where domain isn't set in
+ # /etc/resolv.conf and the search list has the hostname domain
+ # not first. We could end up with the wrong SRV record.
domains = self.__get_resolver_domains()
- domains = [domain] + domains
- for domain in domains:
- (server, domain) = self.check_domain(domain)
+ domains = [(domain, 'domain of the hostname')] + domains
+ tried = set()
+ for domain, reason in domains:
+ server, domain = self.check_domain(domain, tried, reason)
if server:
self.server = server
self.domain = domain
+ self.server_source = self.domain_source = (
+ 'Discovered LDAP SRV records from %s (%s)' %
+ (domain, reason))
break
if not self.domain: #no ldap server found
+ root_logger.debug('No LDAP server found')
return NO_LDAP_SERVER
else:
root_logger.debug("Search for LDAP SRV record in %s", domain)
@@ -156,25 +187,34 @@ class IPADiscovery:
if server:
self.server = server[0]
self.domain = domain
+ self.server_source = self.domain_source = (
+ 'Discovered LDAP SRV records from %s' % domain)
else:
self.server = None
+ root_logger.debug('No LDAP server found')
return NO_LDAP_SERVER
- else: #server forced on us, this means DNS doesn't work :/
+ else:
+ root_logger.debug("Server and domain forced")
self.domain = domain
self.server = server
+ self.domain_source = self.server_source = 'Forced'
#search for kerberos
- root_logger.debug("[ipadnssearchkrb]")
- krbret = self.ipadnssearchkrb(self.domain)
- if not server and not krbret[0]:
+ root_logger.debug("[Kerberos realm search]")
+ krb_realm, kdc = self.ipadnssearchkrb(self.domain)
+ if not server and not krb_realm:
return REALM_NOT_FOUND
- self.realm = krbret[0]
- self.kdc = krbret[1]
+ self.realm = krb_realm
+ self.kdc = kdc
+ self.realm_source = self.kdc_source = (
+ 'Discovered Kerberos DNS records from %s' % self.domain)
- root_logger.debug("[ipacheckldap]")
+ root_logger.debug("[LDAP server check]")
+ root_logger.debug('Verifying that %s (realm %s) is an IPA server',
+ self.server, self.realm)
# We may have received multiple servers corresponding to the domain
# Iterate through all of those to check if it is IPA LDAP server
ldapret = [NOT_IPA_SERVER]
@@ -186,10 +226,12 @@ class IPADiscovery:
if ldapret[0] == 0:
self.server = ldapret[1]
self.realm = ldapret[2]
+ self.server_source = self.realm_source = (
+ 'Discovered from LDAP DNS records in %s' % self.server)
elif ldapret[0] == NO_ACCESS_TO_LDAP:
ldapaccess = False
- # If one of LDAP servers checked rejects access (may be anonymous
+ # If one of LDAP servers checked rejects access (maybe anonymous
# bind is disabled), assume realm and basedn generated off domain.
# Note that in case ldapret[0] == 0 and ldapaccess == False (one of
# servers didn't provide access but another one succeeded), self.realm
@@ -198,12 +240,20 @@ class IPADiscovery:
if not ldapaccess and self.realm is None:
# Assume realm is the same as domain.upper()
self.realm = self.domain.upper()
- root_logger.debug("Assuming realm is the same as domain: %s" % self.realm)
+ self.realm_source = 'Assumed same as domain'
+ root_logger.debug(
+ "Assuming realm is the same as domain: %s", self.realm)
if not ldapaccess and self.basedn is None:
# Generate suffix from realm
self.basedn = realm_to_suffix(self.realm)
- root_logger.debug("Generate basedn from realm: %s" % self.basedn)
+ self.basedn_source = 'Generated from Kerberos realm'
+ root_logger.debug("Generated basedn from realm: %s" % self.basedn)
+
+ root_logger.debug(
+ "Discovery result: %s; server=%s, domain=%s, kdc=%s, basedn=%s",
+ error_names.get(ldapret[0], ldapret[0]),
+ self.server, self.domain, self.kdc, self.basedn)
return ldapret[0]
@@ -222,10 +272,6 @@ class IPADiscovery:
2 means the server is certainly not an IPA server
"""
- lret = []
- lres = []
- lattr = ""
- linfo = ""
lrealms = []
i = 0
@@ -241,13 +287,14 @@ class IPADiscovery:
run(["/usr/bin/wget", "-O", "%s/ca.crt" % temp_ca_dir, "-T", "15", "-t", "2",
"http://%s/ipa/config/ca.crt" % format_netloc(thost)])
except CalledProcessError, e:
- root_logger.debug('Retrieving CA from %s failed.\n%s' % (thost, str(e)))
+ root_logger.debug('Retrieving CA from %s failed: %s', thost, str(e))
return [NOT_IPA_SERVER]
#now verify the server is really an IPA server
try:
- root_logger.debug("Init ldap with: ldap://"+format_netloc(thost, 389))
- lh = ldap.initialize("ldap://"+format_netloc(thost, 389))
+ ldap_url = "ldap://" + format_netloc(thost, 389)
+ root_logger.debug("Init LDAP connection with: %s", ldap_url)
+ lh = ldap.initialize(ldap_url)
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True)
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, "%s/ca.crt" % temp_ca_dir)
lh.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
@@ -260,19 +307,23 @@ class IPADiscovery:
basedn = get_ipa_basedn(lh)
if basedn is None:
+ root_logger.debug("The server is not an IPA server")
return [NOT_IPA_SERVER]
self.basedn = basedn
+ self.basedn_source = 'From IPA server %s' % ldap_url
#search and return known realms
- root_logger.debug("Search for (objectClass=krbRealmContainer) in "+self.basedn+"(sub)")
+ root_logger.debug(
+ "Search for (objectClass=krbRealmContainer) in %s (sub)",
+ self.basedn)
lret = lh.search_s("cn=kerberos,"+self.basedn, ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)")
if not lret:
#something very wrong
return [REALM_NOT_FOUND]
- root_logger.debug("Found: "+str(lret))
for lres in lret:
+ root_logger.debug("Found: %s", lres[0])
for lattr in lres[1]:
if lattr.lower() == "cn":
lrealms.append(lres[1][lattr][0])
@@ -316,7 +367,7 @@ class IPADiscovery:
break_on_first=True):
"""
Search for SRV records in given domain. When no record is found,
- en empty string is returned
+ en empty list is returned
:param domain: Search domain name
:param srv_record_name: SRV record name, e.g. "_ldap._tcp"
@@ -386,4 +437,4 @@ class IPADiscovery:
kdc = None
kdc = ','.join(kdc)
- return [realm, kdc]
+ return realm, kdc