diff options
Diffstat (limited to 'ipalib')
-rw-r--r-- | ipalib/conn.py | 72 | ||||
-rw-r--r-- | ipalib/ipaldap.py | 627 | ||||
-rw-r--r-- | ipalib/ipautil.py | 190 | ||||
-rw-r--r-- | ipalib/servercore.py | 148 |
4 files changed, 0 insertions, 1037 deletions
diff --git a/ipalib/conn.py b/ipalib/conn.py deleted file mode 100644 index f8f5306f..00000000 --- a/ipalib/conn.py +++ /dev/null @@ -1,72 +0,0 @@ -# Authors: Rob Crittenden <rcritten@redhat.com> -# -# Copyright (C) 2008 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 only -# -# 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 krbV -import threading -import ldap -import ldap.dn -from ipalib import ipaldap - -context = threading.local() - -class IPAConn: - def __init__(self, host, port, krbccache, debug=None): - self._conn = None - - # Save the arguments - self._host = host - self._port = port - self._krbccache = krbccache - self._debug = debug - - self._ctx = krbV.default_context() - - ccache = krbV.CCache(name=krbccache, context=self._ctx) - cprinc = ccache.principal() - - self._conn = ipaldap.IPAdmin(host,port,None,None,None,debug) - - # This will bind the connection - try: - self._conn.set_krbccache(krbccache, cprinc.name) - except ldap.UNWILLING_TO_PERFORM, e: - raise e - except Exception, e: - raise e - - def __del__(self): - # take no chances on unreleased connections - self.releaseConn() - - def getConn(self): - return self._conn - - def releaseConn(self): - if self._conn is None: - return - - self._conn.unbind_s() - self._conn = None - - return - -if __name__ == "__main__": - ipaconn = IPAConn("localhost", 389, "FILE:/tmp/krb5cc_500") - x = ipaconn.getConn().getEntry("dc=example,dc=com", ldap.SCOPE_SUBTREE, "uid=admin", ["cn"]) - print "%s" % x diff --git a/ipalib/ipaldap.py b/ipalib/ipaldap.py deleted file mode 100644 index c1d134a0..00000000 --- a/ipalib/ipaldap.py +++ /dev/null @@ -1,627 +0,0 @@ -# Authors: Rich Megginson <richm@redhat.com> -# Rob Crittenden <rcritten@redhat.com -# -# 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 only -# -# 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 sys -import os -import os.path -import base64 -import urllib -import socket -import ldif -import re -import string -import ldap -import cStringIO -import struct -import ldap.sasl -from ldap.controls import LDAPControl,DecodeControlTuples,EncodeControlTuples -from ldap.ldapobject import SimpleLDAPObject -import ipautil - -# Global variable to define SASL auth -sasl_auth = ldap.sasl.sasl({},'GSSAPI') - -class Entry: - """This class represents an LDAP Entry object. An LDAP entry consists of a DN - and a list of attributes. Each attribute consists of a name and a list of - values. In python-ldap, entries are returned as a list of 2-tuples. - Instance variables: - dn - string - the string DN of the entry - data - CIDict - case insensitive dict of the attributes and values""" - - def __init__(self,entrydata): - """data is the raw data returned from the python-ldap result method, which is - a search result entry or a reference or None. - If creating a new empty entry, data is the string DN.""" - if entrydata: - if isinstance(entrydata,tuple): - self.dn = entrydata[0] - self.data = ipautil.CIDict(entrydata[1]) - elif isinstance(entrydata,str) or isinstance(entrydata,unicode): - self.dn = entrydata - self.data = ipautil.CIDict() - else: - self.dn = '' - self.data = ipautil.CIDict() - - def __nonzero__(self): - """This allows us to do tests like if entry: returns false if there is no data, - true otherwise""" - return self.data != None and len(self.data) > 0 - - def hasAttr(self,name): - """Return True if this entry has an attribute named name, False otherwise""" - return self.data and self.data.has_key(name) - - def __getattr__(self,name): - """If name is the name of an LDAP attribute, return the first value for that - attribute - equivalent to getValue - this allows the use of - entry.cn - instead of - entry.getValue('cn') - This also allows us to return None if an attribute is not found rather than - throwing an exception""" - return self.getValue(name) - - def getValues(self,name): - """Get the list (array) of values for the attribute named name""" - return self.data.get(name) - - def getValue(self,name): - """Get the first value for the attribute named name""" - return self.data.get(name,[None])[0] - - def setValue(self,name,*value): - """Value passed in may be a single value, several values, or a single sequence. - For example: - ent.setValue('name', 'value') - ent.setValue('name', 'value1', 'value2', ..., 'valueN') - ent.setValue('name', ['value1', 'value2', ..., 'valueN']) - ent.setValue('name', ('value1', 'value2', ..., 'valueN')) - Since *value is a tuple, we may have to extract a list or tuple from that - tuple as in the last two examples above""" - if isinstance(value[0],list) or isinstance(value[0],tuple): - self.data[name] = value[0] - else: - self.data[name] = value - - setValues = setValue - - def toTupleList(self): - """Convert the attrs and values to a list of 2-tuples. The first element - of the tuple is the attribute name. The second element is either a - single value or a list of values.""" - return self.data.items() - - def __str__(self): - """Convert the Entry to its LDIF representation""" - return self.__repr__() - - # the ldif class base64 encodes some attrs which I would rather see in raw form - to - # encode specific attrs as base64, add them to the list below - ldif.safe_string_re = re.compile('^$') - base64_attrs = ['nsstate', 'krbprincipalkey', 'krbExtraData'] - - def __repr__(self): - """Convert the Entry to its LDIF representation""" - sio = cStringIO.StringIO() - # what's all this then? the unparse method will currently only accept - # a list or a dict, not a class derived from them. self.data is a - # cidict, so unparse barfs on it. I've filed a bug against python-ldap, - # but in the meantime, we have to convert to a plain old dict for printing - # I also don't want to see wrapping, so set the line width really high (1000) - newdata = {} - newdata.update(self.data) - ldif.LDIFWriter(sio,Entry.base64_attrs,1000).unparse(self.dn,newdata) - return sio.getvalue() - -def wrapper(f,name): - """This is the method that wraps all of the methods of the superclass. This seems - to need to be an unbound method, that's why it's outside of IPAdmin. Perhaps there - is some way to do this with the new classmethod or staticmethod of 2.4. - Basically, we replace every call to a method in SimpleLDAPObject (the superclass - of IPAdmin) with a call to inner. The f argument to wrapper is the bound method - of IPAdmin (which is inherited from the superclass). Bound means that it will implicitly - be called with the self argument, it is not in the args list. name is the name of - the method to call. If name is a method that returns entry objects (e.g. result), - we wrap the data returned by an Entry class. If name is a method that takes an entry - argument, we extract the raw data from the entry object to pass in.""" - def inner(*args, **kargs): - if name == 'result': - objtype, data = f(*args, **kargs) - # data is either a 2-tuple or a list of 2-tuples - # print data - if data: - if isinstance(data,tuple): - return objtype, Entry(data) - elif isinstance(data,list): - return objtype, [Entry(x) for x in data] - else: - raise TypeError, "unknown data type %s returned by result" % type(data) - else: - return objtype, data - elif name.startswith('add'): - # the first arg is self - # the second and third arg are the dn and the data to send - # We need to convert the Entry into the format used by - # python-ldap - ent = args[0] - if isinstance(ent,Entry): - return f(ent.dn, ent.toTupleList(), *args[2:]) - else: - return f(*args, **kargs) - else: - return f(*args, **kargs) - return inner - -class LDIFConn(ldif.LDIFParser): - def __init__( - self, - input_file, - ignored_attr_types=None,max_entries=0,process_url_schemes=None - ): - """ - See LDIFParser.__init__() - - Additional Parameters: - all_records - List instance for storing parsed records - """ - self.dndict = {} # maps dn to Entry - self.dnlist = [] # contains entries in order read - myfile = input_file - if isinstance(input_file,str) or isinstance(input_file,unicode): - myfile = open(input_file, "r") - ldif.LDIFParser.__init__(self,myfile,ignored_attr_types,max_entries,process_url_schemes) - self.parse() - if isinstance(input_file,str) or isinstance(input_file,unicode): - myfile.close() - - def handle(self,dn,entry): - """ - Append single record to dictionary of all records. - """ - if not dn: - dn = '' - newentry = Entry((dn, entry)) - self.dndict[IPAdmin.normalizeDN(dn)] = newentry - self.dnlist.append(newentry) - - def get(self,dn): - ndn = IPAdmin.normalizeDN(dn) - return self.dndict.get(ndn, Entry(None)) - -class IPAdmin(SimpleLDAPObject): - - def getDseAttr(self,attrname): - conffile = self.confdir + '/dse.ldif' - dseldif = LDIFConn(conffile) - cnconfig = dseldif.get("cn=config") - if cnconfig: - return cnconfig.getValue(attrname) - return None - - def __initPart2(self): - if self.binddn and len(self.binddn) and not hasattr(self,'sroot'): - try: - ent = self.getEntry('cn=config', ldap.SCOPE_BASE, '(objectclass=*)', - [ 'nsslapd-instancedir', 'nsslapd-errorlog', - 'nsslapd-certdir', 'nsslapd-schemadir' ]) - self.errlog = ent.getValue('nsslapd-errorlog') - self.confdir = ent.getValue('nsslapd-certdir') - if not self.confdir: - self.confdir = ent.getValue('nsslapd-schemadir') - if self.confdir: - self.confdir = os.path.dirname(self.confdir) - ent = self.getEntry('cn=config,cn=ldbm database,cn=plugins,cn=config', - ldap.SCOPE_BASE, '(objectclass=*)', - [ 'nsslapd-directory' ]) - self.dbdir = os.path.dirname(ent.getValue('nsslapd-directory')) - except (ldap.INSUFFICIENT_ACCESS, ldap.CONNECT_ERROR): - pass # usually means - except ldap.LDAPError, e: - print "caught exception ", e - raise - - def __localinit(self): - """If a CA certificate is provided then it is assumed that we are - doing SSL client authentication with proxy auth. - - If a CA certificate is not present then it is assumed that we are - using a forwarded kerberos ticket for SASL auth. SASL provides - its own encryption. - """ - if self.cacert is not None: - SimpleLDAPObject.__init__(self,'ldaps://%s:%d' % (self.host,self.port)) - else: - SimpleLDAPObject.__init__(self,'ldap://%s:%d' % (self.host,self.port)) - - def __init__(self,host,port=389,cacert=None,bindcert=None,bindkey=None,proxydn=None,debug=None): - """We just set our instance variables and wrap the methods - the real - work is done in __localinit and __initPart2 - these are separated - out this way so that we can call them from places other than - instance creation e.g. when we just need to reconnect, not create a - new instance""" - if debug and debug.lower() == "on": - ldap.set_option(ldap.OPT_DEBUG_LEVEL,255) - if cacert is not None: - ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,cacert) - if bindcert is not None: - ldap.set_option(ldap.OPT_X_TLS_CERTFILE,bindcert) - if bindkey is not None: - ldap.set_option(ldap.OPT_X_TLS_KEYFILE,bindkey) - - self.__wrapmethods() - self.port = port - self.host = host - self.cacert = cacert - self.bindcert = bindcert - self.bindkey = bindkey - self.proxydn = proxydn - self.suffixes = {} - self.__localinit() - - def __str__(self): - return self.host + ":" + str(self.port) - - def __get_server_controls(self): - """Create the proxy user server control. The control has the form - 0x04 = Octet String - 4|0x80 sets the length of the string length field at 4 bytes - the struct() gets us the length in bytes of string self.proxydn - self.proxydn is the proxy dn to send""" - - if self.proxydn is not None: - proxydn = chr(0x04) + chr(4|0x80) + struct.pack('l', socket.htonl(len(self.proxydn))) + self.proxydn; - - # Create the proxy control - sctrl=[] - sctrl.append(LDAPControl('2.16.840.1.113730.3.4.18',True,proxydn)) - else: - sctrl=None - - return sctrl - - def toLDAPURL(self): - return "ldap://%s:%d/" % (self.host,self.port) - - def set_proxydn(self, proxydn): - self.proxydn = proxydn - - def set_krbccache(self, krbccache, principal): - if krbccache is not None: - os.environ["KRB5CCNAME"] = krbccache - self.sasl_interactive_bind_s("", sasl_auth) - self.principal = principal - self.proxydn = None - - def do_simple_bind(self, binddn="cn=directory manager", bindpw=""): - self.binddn = binddn - self.bindpwd = bindpw - self.simple_bind_s(binddn, bindpw) - self.__initPart2() - - def getEntry(self,*args): - """This wraps the search function. It is common to just get one entry""" - - sctrl = self.__get_server_controls() - - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - - try: - res = self.search(*args) - objtype, obj = self.result(res) - except ldap.NO_SUCH_OBJECT, e: - raise e - except ldap.LDAPError, e: - raise e - - if not obj: - raise ldap.NO_SUCH_OBJECT - - elif isinstance(obj,Entry): - return obj - else: # assume list/tuple - return obj[0] - - def getList(self,*args): - """This wraps the search function to find multiple entries.""" - - sctrl = self.__get_server_controls() - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - - try: - res = self.search(*args) - objtype, obj = self.result(res) - except (ldap.ADMINLIMIT_EXCEEDED, ldap.SIZELIMIT_EXCEEDED), e: - # Too many results returned by search - raise e - except ldap.LDAPError, e: - raise e - - if not obj: - raise ldap.NO_SUCH_OBJECT - - entries = [] - for s in obj: - entries.append(s) - - return entries - - def getListAsync(self,*args): - """This version performs an asynchronous search, to allow - results even if we hit a limit. - - It returns a list: counter followed by the results. - If the results are truncated, counter will be set to -1. - """ - - sctrl = self.__get_server_controls() - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - - entries = [] - partial = 0 - - try: - msgid = self.search_ext(*args) - objtype, result_list = self.result(msgid, 0) - while result_list: - for result in result_list: - entries.append(result) - objtype, result_list = self.result(msgid, 0) - except (ldap.ADMINLIMIT_EXCEEDED, ldap.SIZELIMIT_EXCEEDED, - ldap.TIMELIMIT_EXCEEDED), e: - partial = 1 - except ldap.LDAPError, e: - raise e - - if not entries: - raise ldap.NO_SUCH_OBJECT - - if partial == 1: - counter = -1 - else: - counter = len(entries) - - return [counter] + entries - - def addEntry(self,*args): - """This wraps the add function. It assumes that the entry is already - populated with all of the desired objectclasses and attributes""" - - sctrl = self.__get_server_controls() - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.add_s(*args) - except ldap.ALREADY_EXISTS, e: - # duplicate value - raise e - except ldap.LDAPError, e: - raise e - return True - - def updateRDN(self, dn, newrdn): - """Wrap the modrdn function.""" - - sctrl = self.__get_server_controls() - - if dn == newrdn: - # no need to report an error - return True - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.modrdn_s(dn, newrdn, delold=1) - except ldap.LDAPError, e: - raise e - return True - - def updateEntry(self,dn,oldentry,newentry): - """This wraps the mod function. It assumes that the entry is already - populated with all of the desired objectclasses and attributes""" - - sctrl = self.__get_server_controls() - - modlist = self.generateModList(oldentry, newentry) - - if len(modlist) == 0: - # FIXME: better error - raise SyntaxError("empty modlist") - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.modify_s(dn, modlist) - # this is raised when a 'delete' attribute isn't found. - # it indicates the previous attribute was removed by another - # update, making the oldentry stale. - except ldap.NO_SUCH_ATTRIBUTE: - # FIXME: better error - raise SyntaxError("mid-air collision") - except ldap.LDAPError, e: - raise e - return True - - def generateModList(self, old_entry, new_entry): - """A mod list generator that computes more precise modification lists - than the python-ldap version. This version purposely generates no - REPLACE operations, to deal with multi-user updates more properly.""" - modlist = [] - - old_entry = ipautil.CIDict(old_entry) - new_entry = ipautil.CIDict(new_entry) - - keys = set(map(string.lower, old_entry.keys())) - keys.update(map(string.lower, new_entry.keys())) - - for key in keys: - new_values = new_entry.get(key, []) - if not(isinstance(new_values,list) or isinstance(new_values,tuple)): - new_values = [new_values] - new_values = filter(lambda value:value!=None, new_values) - new_values = set(new_values) - - old_values = old_entry.get(key, []) - if not(isinstance(old_values,list) or isinstance(old_values,tuple)): - old_values = [old_values] - old_values = filter(lambda value:value!=None, old_values) - old_values = set(old_values) - - adds = list(new_values.difference(old_values)) - removes = list(old_values.difference(new_values)) - - if len(removes) > 0: - modlist.append((ldap.MOD_DELETE, key, removes)) - if len(adds) > 0: - modlist.append((ldap.MOD_ADD, key, adds)) - - return modlist - - def inactivateEntry(self,dn,has_key): - """Rather than deleting entries we mark them as inactive. - has_key defines whether the entry already has nsAccountlock - set so we can determine which type of mod operation to run.""" - - sctrl = self.__get_server_controls() - modlist=[] - - if has_key: - operation = ldap.MOD_REPLACE - else: - operation = ldap.MOD_ADD - - modlist.append((operation, "nsAccountlock", "true")) - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.modify_s(dn, modlist) - except ldap.LDAPError, e: - raise e - return True - - def deleteEntry(self,*args): - """This wraps the delete function. Use with caution.""" - - sctrl = self.__get_server_controls() - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.delete_s(*args) - except ldap.LDAPError, e: - raise e - return True - - def modifyPassword(self,dn,oldpass,newpass): - """Set the user password using RFC 3062, LDAP Password Modify Extended - Operation. This ends up calling the IPA password slapi plugin - handler so the Kerberos password gets set properly. - - oldpass is not mandatory - """ - - sctrl = self.__get_server_controls() - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.passwd_s(dn, oldpass, newpass) - except ldap.LDAPError, e: - raise e - return True - - def __wrapmethods(self): - """This wraps all methods of SimpleLDAPObject, so that we can intercept - the methods that deal with entries. Instead of using a raw list of tuples - of lists of hashes of arrays as the entry object, we want to wrap entries - in an Entry class that provides some useful methods""" - for name in dir(self.__class__.__bases__[0]): - attr = getattr(self, name) - if callable(attr): - setattr(self, name, wrapper(attr, name)) - - def addSchema(self, attr, val): - dn = "cn=schema" - self.modify_s(dn, [(ldap.MOD_ADD, attr, val)]) - - def addAttr(self, *args): - return self.addSchema('attributeTypes', args) - - def addObjClass(self, *args): - return self.addSchema('objectClasses', args) - - ########################### - # Static methods start here - ########################### - def normalizeDN(dn): - # not great, but will do until we use a newer version of python-ldap - # that has DN utilities - ary = ldap.explode_dn(dn.lower()) - return ",".join(ary) - normalizeDN = staticmethod(normalizeDN) - - def getfqdn(name=''): - return socket.getfqdn(name) - getfqdn = staticmethod(getfqdn) - - def getdomainname(name=''): - fqdn = IPAdmin.getfqdn(name) - index = fqdn.find('.') - if index >= 0: - return fqdn[index+1:] - else: - return fqdn - getdomainname = staticmethod(getdomainname) - - def getdefaultsuffix(name=''): - dm = IPAdmin.getdomainname(name) - if dm: - return "dc=" + dm.replace('.', ', dc=') - else: - return 'dc=localdomain' - getdefaultsuffix = staticmethod(getdefaultsuffix) - - def is_a_dn(dn): - """Returns True if the given string is a DN, False otherwise.""" - return (dn.find("=") > 0) - is_a_dn = staticmethod(is_a_dn) - - -def notfound(args): - """Return a string suitable for displaying as an error when a - search returns no results. - - This just returns whatever is after the equals sign""" - if len(args) > 2: - searchfilter = args[2] - try: - target = re.match(r'\(.*=(.*)\)', searchfilter).group(1) - except: - target = searchfilter - return "%s not found" % str(target) - else: - return args[0] diff --git a/ipalib/ipautil.py b/ipalib/ipautil.py deleted file mode 100644 index 6b0e2c89..00000000 --- a/ipalib/ipautil.py +++ /dev/null @@ -1,190 +0,0 @@ -# Authors: Simo Sorce <ssorce@redhat.com> -# -# 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 only -# -# 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 string -import xmlrpclib -import re - -def realm_to_suffix(realm_name): - s = realm_name.split(".") - terms = ["dc=" + x.lower() for x in s] - return ",".join(terms) - -class CIDict(dict): - """ - Case-insensitive but case-respecting dictionary. - - This code is derived from python-ldap's cidict.py module, - written by stroeder: http://python-ldap.sourceforge.net/ - - This version extends 'dict' so it works properly with TurboGears. - If you extend UserDict, isinstance(foo, dict) returns false. - """ - - def __init__(self,default=None): - super(CIDict, self).__init__() - self._keys = {} - self.update(default or {}) - - def __getitem__(self,key): - return super(CIDict,self).__getitem__(string.lower(key)) - - def __setitem__(self,key,value): - lower_key = string.lower(key) - self._keys[lower_key] = key - return super(CIDict,self).__setitem__(string.lower(key),value) - - def __delitem__(self,key): - lower_key = string.lower(key) - del self._keys[lower_key] - return super(CIDict,self).__delitem__(string.lower(key)) - - def update(self,dict): - for key in dict.keys(): - self[key] = dict[key] - - def has_key(self,key): - return super(CIDict, self).has_key(string.lower(key)) - - def get(self,key,failobj=None): - try: - return self[key] - except KeyError: - return failobj - - def keys(self): - return self._keys.values() - - def items(self): - result = [] - for k in self._keys.values(): - result.append((k,self[k])) - return result - - def copy(self): - copy = {} - for k in self._keys.values(): - copy[k] = self[k] - return copy - - def iteritems(self): - return self.copy().iteritems() - - def iterkeys(self): - return self.copy().iterkeys() - - def setdefault(self,key,value=None): - try: - return self[key] - except KeyError: - self[key] = value - return value - - def pop(self, key, *args): - try: - value = self[key] - del self[key] - return value - except KeyError: - if len(args) == 1: - return args[0] - raise - - def popitem(self): - (lower_key,value) = super(CIDict,self).popitem() - key = self._keys[lower_key] - del self._keys[lower_key] - - return (key,value) - - -# -# The safe_string_re regexp and needs_base64 function are extracted from the -# python-ldap ldif module, which was -# written by Michael Stroeder <michael@stroeder.com> -# http://python-ldap.sourceforge.net -# -# It was extracted because ipaldap.py is naughtily reaching into the ldif -# module and squashing this regexp. -# -SAFE_STRING_PATTERN = '(^(\000|\n|\r| |:|<)|[\000\n\r\200-\377]+|[ ]+$)' -safe_string_re = re.compile(SAFE_STRING_PATTERN) - -def needs_base64(s): - """ - returns 1 if s has to be base-64 encoded because of special chars - """ - return not safe_string_re.search(s) is None - - -def wrap_binary_data(data): - """Converts all binary data strings into Binary objects for transport - back over xmlrpc.""" - if isinstance(data, str): - if needs_base64(data): - return xmlrpclib.Binary(data) - else: - return data - elif isinstance(data, list) or isinstance(data,tuple): - retval = [] - for value in data: - retval.append(wrap_binary_data(value)) - return retval - elif isinstance(data, dict): - retval = {} - for (k,v) in data.iteritems(): - retval[k] = wrap_binary_data(v) - return retval - else: - return data - - -def unwrap_binary_data(data): - """Converts all Binary objects back into strings.""" - if isinstance(data, xmlrpclib.Binary): - # The data is decoded by the xmlproxy, but is stored - # in a binary object for us. - return str(data) - elif isinstance(data, str): - return data - elif isinstance(data, list) or isinstance(data,tuple): - retval = [] - for value in data: - retval.append(unwrap_binary_data(value)) - return retval - elif isinstance(data, dict): - retval = {} - for (k,v) in data.iteritems(): - retval[k] = unwrap_binary_data(v) - return retval - else: - return data - -def get_gsserror(e): - """A GSSError exception looks differently in python 2.4 than it does - in python 2.5, deal with it.""" - - try: - primary = e[0] - secondary = e[1] - except: - primary = e[0][0] - secondary = e[0][1] - - return (primary[0], secondary[0]) diff --git a/ipalib/servercore.py b/ipalib/servercore.py deleted file mode 100644 index 8626c04b..00000000 --- a/ipalib/servercore.py +++ /dev/null @@ -1,148 +0,0 @@ -# Authors: Rob Crittenden <rcritten@redhat.com> -# -# 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 only -# -# 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 sys -sys.path.insert(0, ".") -sys.path.insert(0, "..") -import ldap -from ipalib.conn import context -from ipalib import ipautil - -# temporary -import krbV - -krbctx = krbV.default_context() -realm = krbctx.default_realm -basedn = ipautil.realm_to_suffix(realm) - -def convert_entry(ent): - entry = dict(ent.data) - entry['dn'] = ent.dn - # For now convert single entry lists to a string for the ui. - # TODO: we need to deal with multi-values better - for key,value in entry.iteritems(): - if isinstance(value,list) or isinstance(value,tuple): - if len(value) == 0: - entry[key] = '' - elif len(value) == 1: - entry[key] = value[0] - return entry - -def convert_scalar_values(orig_dict): - """LDAP update dicts expect all values to be a list (except for dn). - This method converts single entries to a list.""" - new_dict={} - for (k,v) in orig_dict.iteritems(): - if not isinstance(v, list) and k != 'dn': - v = [v] - new_dict[k] = v - - return new_dict - - -# TODO: rethink the get_entry vs get_list API calls. -# they currently restrict the data coming back without -# restricting scope. For now adding a get_base/sub_entry() -# calls, but the API isn't great. -def get_entry (base, scope, searchfilter, sattrs=None): - """Get a specific entry (with a parametized scope). - Return as a dict of values. - Multi-valued fields are represented as lists. - """ - ent="" - - ent = context.conn.getConn().getEntry(base, scope, searchfilter, sattrs) - - return convert_entry(ent) - -def get_base_entry (base, searchfilter, sattrs=None): - """Get a specific entry (with a scope of BASE). - Return as a dict of values. - Multi-valued fields are represented as lists. - """ - return get_entry(base, ldap.SCOPE_BASE, searchfilter, sattrs) - -def get_sub_entry (base, searchfilter, sattrs=None): - """Get a specific entry (with a scope of SUB). - Return as a dict of values. - Multi-valued fields are represented as lists. - """ - return get_entry(base, ldap.SCOPE_SUBTREE, searchfilter, sattrs) - -def get_list (base, searchfilter, sattrs=None): - """Gets a list of entries. Each is converted to a dict of values. - Multi-valued fields are represented as lists. - """ - entries = [] - - entries = context.conn.getConn().getList(base, ldap.SCOPE_SUBTREE, searchfilter, sattrs) - - return map(convert_entry, entries) - -def update_entry (oldentry, newentry): - """Update an LDAP entry - - oldentry is a dict - newentry is a dict - """ - oldentry = convert_scalar_values(oldentry) - newentry = convert_scalar_values(newentry) - - # Should be able to get this from either the old or new entry - # but just in case someone has decided to try changing it, use the - # original - try: - moddn = oldentry['dn'] - except KeyError, e: - # FIXME: return a missing DN error message - raise e - - res = context.conn.getConn().updateEntry(moddn, oldentry, newentry) - return res - -def uniq_list(x): - """Return a unique list, preserving order and ignoring case""" - myset = {} - return [set.setdefault(e.lower(),e) for e in x if e.lower() not in myset] - -def get_schema(): - """Retrieves the current LDAP schema from the LDAP server.""" - - schema_entry = get_base_entry("", "objectclass=*", ['dn','subschemasubentry']) - schema_cn = schema_entry.get('subschemasubentry') - schema = get_base_entry(schema_cn, "objectclass=*", ['*']) - - return schema - -def get_objectclasses(): - """Returns a list of available objectclasses that the LDAP - server supports. This parses out the syntax, attributes, etc - and JUST returns a lower-case list of the names.""" - - schema = get_schema() - - objectclasses = schema.get('objectclasses') - - # Convert this list into something more readable - result = [] - for i in range(len(objectclasses)): - oc = objectclasses[i].lower().split(" ") - result.append(oc[3].replace("'","")) - - return result |