From 0e419aa4bf95a9251b88f7878d368c4d9b123cc7 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 16 Aug 2007 18:00:16 -0400 Subject: Add a prototype client tool to configure a client of the IPA server Right now it does only discovery (or fallback) --- ipa-client/ipaclient/ipadiscovery.py | 239 +++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 ipa-client/ipaclient/ipadiscovery.py (limited to 'ipa-client/ipaclient/ipadiscovery.py') diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py new file mode 100644 index 000000000..312c8ba4b --- /dev/null +++ b/ipa-client/ipaclient/ipadiscovery.py @@ -0,0 +1,239 @@ +#! /usr/bin/python -E +# Authors: Simo Sorce +# +# Copyright (C) 2007 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; version 2 or later +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import socket +import logging +import dnsclient +import ldap +from ldap import LDAPError + +class IPADiscovery: + + def __init__(self): + self.realm = None + self.domain = None + self.server = None + + def getServerName(self): + return str(self.server) + + def getDomainName(self): + return str(self.domain) + + def getRealmName(self): + return str(self.realm) + + def search(self, domain = "", server = ""): + hostname = "" + qname = "" + results = [] + result = [] + krbret = [] + ldapret = [] + + if not server: + + if not domain: #domain not provided do full DNS discovery + + # get the local host name + hostname = socket.getfqdn() + if not hostname: + return -10 #bad host configuration + + # first, check for an LDAP server for the local domain + p = hostname.find(".") + if p == -1: #no domain name + return -1 + domain = hostname[p+1:] + + while not self.server: + logging.debug("[ipadnssearchldap("+domain+")]") + self.server = self.ipadnssearchldap(domain) + if self.server: + self.domain = domain + else: + p = domain.find(".") + if p == -1: #no ldap server found and last component of the domain already tested + return -1 + domain = domain[p+1:] + else: + logging.debug("[ipadnssearchldap]") + self.server = self.ipadnssearchldap(domain) + if self.server: + self.domain = domain + else: + return -2 #no ldap server found + + + #search for kerberos TODO: move this after ipacheckldap() + logging.debug("[ipadnssearchkrb]") + krbret = self.ipadnssearchkrb(self.domain) + if not krbret: + return -3 #no krb server found + + self.realm = krbret[0] + + else: #server forced on us, this means DNS doesn't work :/ + + self.domain = domain + self.server = server + + logging.debug("[ipacheckldap]") + # check ldap now + ldapret = self.ipacheckldap(self.server, self.realm); + + if not ldapret: + return -4 # not an IPA server (or broken config) + + self.server = ldapret[0] + self.realm = ldapret[1] + + return 0 + + def ipacheckldap(self, thost, trealm): + + lret = [] + lres = [] + lattr = "" + linfo = "" + lrealms = [] + + i = 0 + + #now verify the server is really an IPA server + try: + logging.debug("Init ldap with: ldap://"+thost+":389") + lh = ldap.initialize("ldap://"+thost+":389") + lh.simple_bind_s("","") + + logging.debug("Search rootdse") + lret = lh.search_s("", ldap.SCOPE_BASE, "(objectClass=*)") + for lattr in lret[0][1]: + if lattr.lower() == "namingcontexts": + lbase = lret[0][1][lattr][0] + + logging.debug("Search for (info=*) in "+lbase+"(base)") + lret = lh.search_s(lbase, ldap.SCOPE_BASE, "(info=IPA*)") + if not lret: + return [] + logging.debug("Found: "+str(lret)) + + for lattr in lret[0][1]: + if lattr.lower() == "info": + linfo = lret[0][1][lattr][0].lower() + break + + if not linfo: + return [] + + #search and return known realms + logging.debug("Search for (objectClass=krbRealmContainer) in "+lbase+"(sub)") + lret = lh.search_s("cn=kerberos,"+lbase, ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)") + if not lret: + #something very wrong + return [] + logging.debug("Found: "+str(lret)) + + for lres in lret: + for lattr in lres[1]: + if lattr.lower() == "cn": + lrealms.append(lres[1][lattr][0]) + + + if trealm: + for r in lrealms: + if trealm == r: + return [thost, trealm] + # must match or something is very wrong + return [] + else: + if len(lrealms) != 1: + #which one? we can't attach to a multi-realm server without DNS working + return [] + else: + return [thost, lrealms[0]] + + #we shouldn't get here + return [] + + except LDAPError, err: + #no good + logging.error("Ldap Error: "+str(err)) + return [] + + + def ipadnssearchldap(self, tdomain): + servers = "" + rserver = "" + + qname = "_ldap._tcp."+tdomain + # terminate the name + if not qname.endswith("."): + qname += "." + results = dnsclient.query(qname, dnsclient.DNS_C_IN, dnsclient.DNS_T_SRV) + + for result in results: + if result.dns_type == dnsclient.DNS_T_SRV: + rserver = result.rdata.server.rstrip(".") + if result.rdata.port and result.rdata.port != 389: + rserver += ":" + str(result.rdata.port) + if servers: + servers += "," + rserver + else: + servers = rserver + break + + return servers + + def ipadnssearchkrb(self, tdomain): + realm = "" + kdc = "" + # now, check for a Kerberos realm the local host or domain is in + qname = "_kerberos." + tdomain + # terminate the name + if not qname.endswith("."): + qname += "." + results = dnsclient.query(qname, dnsclient.DNS_C_IN, dnsclient.DNS_T_TXT) + + for result in results: + if result.dns_type == dnsclient.DNS_T_TXT: + realm = result.rdata.data + if realm: + break + + if realm: + # now fetch server information for the realm + qname = "_kerberos._udp." + tdomain + # terminate the name + if not qname.endswith("."): + qname += "." + results = dnsclient.query(qname, dnsclient.DNS_C_IN, dnsclient.DNS_T_SRV) + for result in results: + if result.dns_type == dnsclient.DNS_T_SRV: + qname = result.rdata.server.rstrip(".") + if result.rdata.port and result.rdata.port != 88: + qname += ":" + str(result.rdata.port) + if kdc: + kdc += "," + qname + else: + kdc = qname + + print "["+realm+", "+kdc+"]" + return [realm, kdc] -- cgit