Make ipa-client-install error messages more understandable and relevant.

* Check remote LDAP server to see if it is a V2 server
* Replace numeric return values with alphanumeric constants
* Display the error message from the ipa-enrollment extended op
* Remove generic join failed error message when XML-RPC fails
* Don't display Certificate subject base when enrollment fails
* Return proper error message when LDAP bind fails

https://fedorahosted.org/freeipa/ticket/1417
This commit is contained in:
Rob Crittenden 2011-07-06 10:30:24 -04:00
parent e8c7eaf260
commit 02df85bb2e
3 changed files with 53 additions and 36 deletions

View File

@ -28,7 +28,7 @@ try:
import logging import logging
import tempfile import tempfile
import getpass import getpass
import ipaclient.ipadiscovery from ipaclient import ipadiscovery
import ipaclient.ipachangeconf import ipaclient.ipachangeconf
import ipaclient.ntpconf import ipaclient.ntpconf
from ipapython.ipautil import run, user_input, CalledProcessError, file_exists from ipapython.ipautil import run, user_input, CalledProcessError, file_exists
@ -703,15 +703,18 @@ def main():
sys.exit('Invalid hostname \'%s\', must be lower-case.' % hostname) sys.exit('Invalid hostname \'%s\', must be lower-case.' % hostname)
# Create the discovery instance # Create the discovery instance
ds = ipaclient.ipadiscovery.IPADiscovery() ds = ipadiscovery.IPADiscovery()
ret = ds.search(domain=options.domain, server=options.server) ret = ds.search(domain=options.domain, server=options.server, hostname=hostname)
if ret == -10: if ret == ipadiscovery.BAD_HOST_CONFIG:
print >>sys.stderr, "Can't get the fully qualified name of this host" print >>sys.stderr, "Can't get the fully qualified name of this host"
print >>sys.stderr, "Please check that the client is properly configured" print >>sys.stderr, "Please check that the client is properly configured"
return ret return ret
if ret == -1 or not ds.getDomainName(): if ret == ipadiscovery.NOT_FQDN:
print >>sys.stderr, "%s is not a fully-qualified hostname" % hostname
return ret
if ret == ipadiscovery.NO_LDAP_SERVER or not ds.getDomainName():
logging.debug("Domain not found") logging.debug("Domain not found")
if options.domain: if options.domain:
cli_domain = options.domain cli_domain = options.domain
@ -722,14 +725,14 @@ def main():
print "DNS discovery failed to determine your DNS domain" print "DNS discovery failed to determine your DNS domain"
cli_domain = user_input("Please provide the domain name of your IPA server (ex: example.com)", allow_empty = False) cli_domain = user_input("Please provide the domain name of your IPA server (ex: example.com)", allow_empty = False)
logging.debug("will use domain: %s\n", cli_domain) logging.debug("will use domain: %s\n", cli_domain)
ret = ds.search(domain=cli_domain, server=options.server) ret = ds.search(domain=cli_domain, server=options.server, hostname=hostname)
if not cli_domain: if not cli_domain:
if ds.getDomainName(): if ds.getDomainName():
cli_domain = ds.getDomainName() cli_domain = ds.getDomainName()
logging.debug("will use domain: %s\n", cli_domain) logging.debug("will use domain: %s\n", cli_domain)
if ret == -2 or not ds.getServerName(): if ret == ipadiscovery.NO_LDAP_SERVER or not ds.getServerName():
logging.debug("IPA Server not found") logging.debug("IPA Server not found")
if options.server: if options.server:
cli_server = options.server cli_server = options.server
@ -740,7 +743,7 @@ def main():
print "DNS discovery failed to find the IPA Server" print "DNS discovery failed to find the IPA Server"
cli_server = user_input("Please provide your IPA server name (ex: ipa.example.com)", allow_empty = False) cli_server = user_input("Please provide your IPA server name (ex: ipa.example.com)", allow_empty = False)
logging.debug("will use server: %s\n", cli_server) logging.debug("will use server: %s\n", cli_server)
ret = ds.search(domain=cli_domain, server=cli_server) ret = ds.search(domain=cli_domain, server=cli_server, hostname=hostname)
else: else:
dnsok = True dnsok = True
if not cli_server: if not cli_server:
@ -748,6 +751,9 @@ def main():
cli_server = ds.getServerName() cli_server = ds.getServerName()
logging.debug("will use server: %s\n", cli_server) logging.debug("will use server: %s\n", cli_server)
if ret == ipadiscovery.NOT_IPA_SERVER:
print >>sys.stderr, "%s is not an IPA v2 Server." % cli_server
return ret
if ret != 0: if ret != 0:
print >>sys.stderr, "Failed to verify that "+cli_server+" is an IPA Server." print >>sys.stderr, "Failed to verify that "+cli_server+" is an IPA Server."
print >>sys.stderr, "This may mean that the remote server is not up or is not reachable" print >>sys.stderr, "This may mean that the remote server is not up or is not reachable"
@ -861,11 +867,7 @@ def main():
(stdout, stderr, returncode) = run(join_args, raiseonerr=False, env=env) (stdout, stderr, returncode) = run(join_args, raiseonerr=False, env=env)
if returncode != 0: if returncode != 0:
if returncode == 17: # XML-RPC fault - possible IPA v1/v2 incompatibility print >>sys.stderr, "Joining realm failed: %s" % stderr,
print "Joining realm failed because of failing XML-RPC request."
print " This error may be caused by incompatible server/client major versions."
else:
print >>sys.stderr, "Joining realm failed: %s" % stderr,
if not options.force: if not options.force:
return 1 return 1
print " Use ipa-getkeytab to obtain a host principal for this server." print " Use ipa-getkeytab to obtain a host principal for this server."

View File

@ -475,15 +475,9 @@ join_ldap(const char *ipaserver, char *hostname, const char ** binddn, const cha
/* Now rebind as the host */ /* Now rebind as the host */
ld = connect_ldap(ipaserver, *binddn, bindpw); ld = connect_ldap(ipaserver, *binddn, bindpw);
if (!ld) { if (!ld) {
if (has_principal) { if (!quiet)
if (!quiet) fprintf(stderr, _("Incorrect password.\n"));
fprintf(stderr, _("Host is already joined.\n")); rval = 15;
rval = 13;
} else {
if (!quiet)
fprintf(stderr, _("Incorrect password.\n"));
rval = 15;
}
goto done; goto done;
} }
@ -491,13 +485,19 @@ join_ldap(const char *ipaserver, char *hostname, const char ** binddn, const cha
valrequest.bv_len = strlen(hostname); valrequest.bv_len = strlen(hostname);
if ((rc = ldap_extended_operation_s(ld, JOIN_OID, &valrequest, NULL, NULL, &oidresult, &valresult)) != LDAP_SUCCESS) { if ((rc = ldap_extended_operation_s(ld, JOIN_OID, &valrequest, NULL, NULL, &oidresult, &valresult)) != LDAP_SUCCESS) {
char *s = NULL;
#ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &s);
#else
ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &s);
#endif
if (!quiet) if (!quiet)
fprintf(stderr, _("principal not found in host entry\n")); fprintf(stderr, _("Enrollment failed. %s\n"), s);
if (debug) { if (debug) {
fprintf(stderr, "ldap_extended_operation_s failed: %s", fprintf(stderr, "ldap_extended_operation_s failed: %s",
ldap_err2string(rc)); ldap_err2string(rc));
} }
rval = 18; rval = 13;
goto ldap_done; goto ldap_done;
} }
@ -1003,7 +1003,7 @@ join(const char *server, const char *hostname, const char *bindpw, const char *k
} }
cleanup: cleanup:
if (NULL != subject && !quiet) if (NULL != subject && !quiet && rval == 0)
fprintf(stderr, _("Certificate subject base is: %s\n"), subject); fprintf(stderr, _("Certificate subject base is: %s\n"), subject);
free((char *)princ); free((char *)princ);

View File

@ -26,6 +26,13 @@ import ldap
from ldap import LDAPError from ldap import LDAPError
from ipapython.ipautil import run, CalledProcessError from ipapython.ipautil import run, CalledProcessError
NOT_FQDN = -1
NO_LDAP_SERVER = -2
REALM_NOT_FOUND = -3
NOT_IPA_SERVER = -4
BAD_HOST_CONFIG = -10
class IPADiscovery: class IPADiscovery:
def __init__(self): def __init__(self):
@ -95,8 +102,7 @@ class IPADiscovery:
domain = domain[p+1:] domain = domain[p+1:]
return (None, None) return (None, None)
def search(self, domain = "", server = ""): def search(self, domain = "", server = "", hostname=None):
hostname = ""
qname = "" qname = ""
results = [] results = []
result = [] result = []
@ -108,14 +114,15 @@ class IPADiscovery:
if not domain: #domain not provided do full DNS discovery if not domain: #domain not provided do full DNS discovery
# get the local host name # get the local host name
hostname = socket.getfqdn()
if not hostname: if not hostname:
return -10 #bad host configuration hostname = socket.getfqdn()
if not hostname:
return BAD_HOST_CONFIG
# first, check for an LDAP server for the local domain # first, check for an LDAP server for the local domain
p = hostname.find(".") p = hostname.find(".")
if p == -1: #no domain name if p == -1: #no domain name
return -1 return NOT_FQDN
domain = hostname[p+1:] domain = hostname[p+1:]
# Get the list of domains from /etc/resolv.conf, we'll search # Get the list of domains from /etc/resolv.conf, we'll search
@ -133,14 +140,14 @@ class IPADiscovery:
self.domain = domain self.domain = domain
break break
if not self.domain: #no ldap server found if not self.domain: #no ldap server found
return -1 return NO_LDAP_SERVER
else: else:
logging.debug("[ipadnssearchldap]") logging.debug("[ipadnssearchldap]")
self.server = self.ipadnssearchldap(domain) self.server = self.ipadnssearchldap(domain)
if self.server: if self.server:
self.domain = domain self.domain = domain
else: else:
return -2 #no ldap server found return NO_LDAP_SERVER
else: #server forced on us, this means DNS doesn't work :/ else: #server forced on us, this means DNS doesn't work :/
@ -151,7 +158,7 @@ class IPADiscovery:
logging.debug("[ipadnssearchkrb]") logging.debug("[ipadnssearchkrb]")
krbret = self.ipadnssearchkrb(self.domain) krbret = self.ipadnssearchkrb(self.domain)
if not server and not krbret[0]: if not server and not krbret[0]:
return -3 # realm for autodiscovery not found return REALM_NOT_FOUND
self.realm = krbret[0] self.realm = krbret[0]
self.kdc = krbret[1] self.kdc = krbret[1]
@ -161,7 +168,7 @@ class IPADiscovery:
ldapret = self.ipacheckldap(self.server, self.realm) ldapret = self.ipacheckldap(self.server, self.realm)
if not ldapret: if not ldapret:
return -4 # not an IPA server (or broken config) return NOT_IPA_SERVER
self.server = ldapret[0] self.server = ldapret[0]
self.realm = ldapret[1] self.realm = ldapret[1]
@ -169,6 +176,14 @@ class IPADiscovery:
return 0 return 0
def ipacheckldap(self, thost, trealm): def ipacheckldap(self, thost, trealm):
"""
Given a host and kerberos realm verify that it is an IPA LDAP
server hosting the realm. The connection is an SSL connection
so the remote IPA CA cert must be available at
http://HOST/ipa/config/ca.crt
Returns a list [host, realm] or an empty list on error.
"""
lret = [] lret = []
lres = [] lres = []
@ -219,7 +234,7 @@ class IPADiscovery:
linfo = lret[0][1][lattr][0].lower() linfo = lret[0][1][lattr][0].lower()
break break
if not linfo: if not linfo or linfo.lower() != 'ipa v2.0':
return [] return []
#search and return known realms #search and return known realms
@ -323,5 +338,5 @@ class IPADiscovery:
if not kdc: if not kdc:
logging.debug("SRV record for KDC not found! Realm: %s, SRV record: %s" % (realm, qname)) logging.debug("SRV record for KDC not found! Realm: %s, SRV record: %s" % (realm, qname))
return [realm, kdc] return [realm, kdc]