summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2007-08-28 10:46:03 -0400
committerSimo Sorce <ssorce@redhat.com>2007-08-28 10:46:03 -0400
commit46eeca740ee4d66bfd4f062896220dfb5527f5b6 (patch)
treeb5a91cf249e823ddb9ab01e9797c742caa90de50
parent4702eb907585556d83b3373bf06705d83ae3ed2d (diff)
parent6eea6664e079d187c3b0420b4283af35205d3b03 (diff)
downloadfreeipa-46eeca740ee4d66bfd4f062896220dfb5527f5b6.tar.gz
freeipa-46eeca740ee4d66bfd4f062896220dfb5527f5b6.tar.xz
freeipa-46eeca740ee4d66bfd4f062896220dfb5527f5b6.zip
Merge in with upstream
-rw-r--r--ipa-python/Makefile2
-rw-r--r--ipa-python/entity.py24
-rw-r--r--ipa-python/ipaclient.py14
-rw-r--r--ipa-python/ipautil.py64
-rw-r--r--ipa-python/rpcclient.py59
-rw-r--r--ipa-server/ipa-gui/ipagui/controllers.py4
-rw-r--r--ipa-server/ipaserver/ipaldap.py10
-rw-r--r--ipa-server/xmlrpc-server/funcs.py163
-rw-r--r--ipa-server/xmlrpc-server/ipaxmlrpc.py14
9 files changed, 237 insertions, 117 deletions
diff --git a/ipa-python/Makefile b/ipa-python/Makefile
index b2e4660f8..542c50820 100644
--- a/ipa-python/Makefile
+++ b/ipa-python/Makefile
@@ -1,4 +1,4 @@
-PYTHONLIBDIR ?= $(shell python -c "from distutils.sysconfig import *; print get_python_lib(1)")
+PYTHONLIBDIR ?= $(shell python -c "from distutils.sysconfig import *; print get_python_lib()")
PACKAGEDIR ?= $(DESTDIR)/$(PYTHONLIBDIR)/ipa
CONFIGDIR ?= $(DESTDIR)/etc/ipa
diff --git a/ipa-python/entity.py b/ipa-python/entity.py
index 9153c4159..2f0629cda 100644
--- a/ipa-python/entity.py
+++ b/ipa-python/entity.py
@@ -3,6 +3,8 @@ import ldif
import re
import cStringIO
+import ipa.ipautil
+
def utf8_encode_value(value):
if isinstance(value,unicode):
return value.encode('utf-8')
@@ -22,8 +24,8 @@ class Entity:
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
- orig_data - cidict - case insentiive dict of the original attributes and values"""
+ data - CIDict - case insensitive dict of the attributes and values
+ orig_data - CIDict - case insentiive dict of the original attributes and values"""
def __init__(self,entrydata=None):
"""data is the raw data returned from the python-ldap result method,
@@ -32,19 +34,19 @@ class Entity:
if entrydata:
if isinstance(entrydata,tuple):
self.dn = entrydata[0]
- self.data = ldap.cidict.cidict(entrydata[1])
+ self.data = ipa.ipautil.CIDict(entrydata[1])
elif isinstance(entrydata,str) or isinstance(entrydata,unicode):
self.dn = entrydata
- self.data = ldap.cidict.cidict()
+ self.data = ipa.ipautil.CIDict()
elif isinstance(entrydata,dict):
self.dn = entrydata['dn']
del entrydata['dn']
- self.data = ldap.cidict.cidict(entrydata)
+ self.data = ipa.ipautil.CIDict(entrydata)
else:
self.dn = ''
- self.data = ldap.cidict.cidict()
+ self.data = ipa.ipautil.CIDict()
- self.orig_data = dict(self.data)
+ self.orig_data = ipa.ipautil.CIDict(self.data)
def __nonzero__(self):
"""This allows us to do tests like if entry: returns false if there is no data,
@@ -112,9 +114,7 @@ class Entity:
def toDict(self):
"""Convert the attrs and values to a dict. The dict is keyed on the
attribute name. The value is either single value or a list of values."""
- result = {}
- for k in self.data.keys():
- result[k] = self.data[k]
+ result = ipa.ipautil.CIDict(self.data)
result['dn'] = self.dn
return result
@@ -124,9 +124,7 @@ class Entity:
def origDataDict(self):
"""Returns a dict of the original values of the user. Used for updates."""
- result = {}
- for k in self.orig_data.keys():
- result[k] = self.orig_data[k]
+ result = ipa.ipautil.CIDict(self.orig_data)
result['dn'] = self.dn
return result
diff --git a/ipa-python/ipaclient.py b/ipa-python/ipaclient.py
index 28573acad..71def70fd 100644
--- a/ipa-python/ipaclient.py
+++ b/ipa-python/ipaclient.py
@@ -30,14 +30,6 @@ import group
import ipa
import config
-def cidict_to_dict(cid):
- """Convert a cidict to a standard dict for sending across the wire"""
- newdict = {}
- kindex = cid.keys()
- for dkey in kindex:
- newdict[dkey] = cid[dkey]
- return newdict
-
class IPAClient:
def __init__(self,local=None):
@@ -89,7 +81,7 @@ class IPAClient:
result = self.transport.get_all_users()
all_users = []
- for (attrs) in result:
+ for attrs in result:
if attrs is not None:
all_users.append(user.User(attrs))
@@ -107,7 +99,7 @@ class IPAClient:
result = self.transport.find_users(criteria, sattrs)
users = []
- for (attrs) in result:
+ for attrs in result:
if attrs is not None:
users.append(user.User(attrs))
@@ -165,7 +157,7 @@ class IPAClient:
result = self.transport.find_groups(criteria, sattrs)
groups = []
- for (attrs) in result:
+ for attrs in result:
if attrs is not None:
groups.append(group.Group(attrs))
diff --git a/ipa-python/ipautil.py b/ipa-python/ipautil.py
index 51337a8eb..74f7cfff6 100644
--- a/ipa-python/ipautil.py
+++ b/ipa-python/ipautil.py
@@ -18,6 +18,8 @@
#
from string import lower
+import re
+import xmlrpclib
class CIDict(dict):
"""
@@ -106,3 +108,65 @@ class CIDict(dict):
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
+
diff --git a/ipa-python/rpcclient.py b/ipa-python/rpcclient.py
index 2301edde8..3e5bb113a 100644
--- a/ipa-python/rpcclient.py
+++ b/ipa-python/rpcclient.py
@@ -29,7 +29,7 @@ import os
import base64
import user
import ipa
-from ipa import ipaerror
+from ipa import ipaerror, ipautil
# Some errors to catch
# http://cvs.fedora.redhat.com/viewcvs/ldapserver/ldap/servers/plugins/pam_passthru/README?root=dirsec&rev=1.6&view=auto
@@ -83,7 +83,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def get_user_by_dn(self,dn,sattrs=None):
"""Get a specific user. If sattrs is not None then only those
@@ -99,7 +99,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def add_user(self,user,user_container=None):
"""Add a new user. Takes as input a dict where the key is the
@@ -111,13 +111,14 @@ class RPCClient:
user_container = "__NONE__"
try:
- result = server.add_user(user, user_container)
+ result = server.add_user(ipautil.wrap_binary_data(user),
+ user_container)
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def get_add_schema(self):
"""Get the list of attributes we need to ask when adding a new
@@ -134,7 +135,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def get_all_users (self):
"""Return a list containing a User object for each existing user."""
@@ -147,7 +148,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def find_users (self, criteria, sattrs=None):
"""Return a list containing a User object for each user that matches
@@ -164,20 +165,21 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def update_user(self,olduser,newuser):
"""Update an existing user. olduser and newuser are dicts of attributes"""
server = self.setup_server()
try:
- result = server.update_user(olduser, newuser)
+ result = server.update_user(ipautil.wrap_binary_data(olduser),
+ ipautil.wrap_binary_data(newuser))
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def mark_user_deleted(self,uid):
"""Mark a user as deleted/inactive"""
@@ -190,7 +192,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
# Group support
@@ -208,7 +210,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def get_group_by_dn(self,dn,sattrs=None):
"""Get a specific group. If sattrs is not None then only those
@@ -224,7 +226,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def add_group(self,group,group_container=None):
"""Add a new group. Takes as input a dict where the key is the
@@ -236,7 +238,8 @@ class RPCClient:
group_container = "__NONE__"
try:
- result = server.add_group(group, group_container)
+ result = server.add_group(ipautil.wrap_binary_data(group),
+ group_container)
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
@@ -257,7 +260,7 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def add_user_to_group(self, user, group):
"""Add a user to an existing group.
@@ -266,13 +269,14 @@ class RPCClient:
"""
server = self.setup_server()
try:
- result = server.add_user_to_group(user, group)
+ result = server.add_user_to_group(ipautil.wrap_binary_data(user),
+ ipautil.wrap_binary_data(group))
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def add_users_to_group(self, users, group):
"""Add several users to an existing group.
@@ -283,13 +287,14 @@ class RPCClient:
"""
server = self.setup_server()
try:
- result = server.add_users_to_group(users, group)
+ result = server.add_users_to_group(ipautil.wrap_binary_data(users),
+ ipautil.wrap_binary_data(group))
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def remove_user_from_group(self, user, group):
"""Remove a user from an existing group.
@@ -298,13 +303,14 @@ class RPCClient:
"""
server = self.setup_server()
try:
- result = server.remove_user_from_group(user, group)
+ result = server.remove_user_from_group(ipautil.wrap_binary_data(user),
+ ipautil.wrap_binary_data(group))
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def remove_users_from_group(self, users, group):
"""Remove several users from an existing group.
@@ -315,23 +321,26 @@ class RPCClient:
"""
server = self.setup_server()
try:
- result = server.remove_users_from_group(users, group)
+ result = server.remove_users_from_group(
+ ipautil.wrap_binary_data(users),
+ ipautil.wrap_binary_data(group))
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
def update_group(self,oldgroup,newgroup):
"""Update an existing group. oldgroup and newgroup are dicts of attributes"""
server = self.setup_server()
try:
- result = server.update_group(oldgroup, newgroup)
+ result = server.update_group(ipautil.wrap_binary_data(oldgroup),
+ ipautil.wrap_binary_data(newgroup))
except xmlrpclib.Fault, fault:
raise ipaerror.gen_exception(fault.faultCode, fault.faultString)
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
- return result
+ return ipautil.unwrap_binary_data(result)
diff --git a/ipa-server/ipa-gui/ipagui/controllers.py b/ipa-server/ipa-gui/ipagui/controllers.py
index eb89e5a6c..7dff9c908 100644
--- a/ipa-server/ipa-gui/ipagui/controllers.py
+++ b/ipa-server/ipa-gui/ipagui/controllers.py
@@ -92,7 +92,7 @@ class Root(controllers.RootController):
if tg_errors:
turbogears.flash("There was a problem with the form!")
- user = client.get_user(uid)
+ user = client.get_user_by_uid(uid)
user_dict = user.toDict()
# store a copy of the original user for the update later
user_data = b64encode(dumps(user_dict))
@@ -155,7 +155,7 @@ class Root(controllers.RootController):
def usershow(self, uid):
"""Retrieve a single user for display"""
try:
- user = client.get_user(uid)
+ user = client.get_user_by_uid(uid)
return dict(user=user.toDict(), fields=forms.user.UserFields())
except ipaerror.IPAError, e:
turbogears.flash("User show failed: " + str(e))
diff --git a/ipa-server/ipaserver/ipaldap.py b/ipa-server/ipaserver/ipaldap.py
index 0b2a152e9..344e6dc3a 100644
--- a/ipa-server/ipaserver/ipaldap.py
+++ b/ipa-server/ipaserver/ipaldap.py
@@ -39,7 +39,7 @@ from ldap.modlist import modifyModlist
from ldap.ldapobject import SimpleLDAPObject
-from ipa import ipaerror
+from ipa import ipaerror, ipautil
class Entry:
"""This class represents an LDAP Entry object. An LDAP entry consists of a DN
@@ -47,7 +47,7 @@ class Entry:
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"""
+ 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
@@ -56,13 +56,13 @@ class Entry:
if entrydata:
if isinstance(entrydata,tuple):
self.dn = entrydata[0]
- self.data = ldap.cidict.cidict(entrydata[1])
+ self.data = ipautil.CIDict(entrydata[1])
elif isinstance(entrydata,str) or isinstance(entrydata,unicode):
self.dn = entrydata
- self.data = ldap.cidict.cidict()
+ self.data = ipautil.CIDict()
else:
self.dn = ''
- self.data = ldap.cidict.cidict()
+ self.data = ipautil.CIDict()
def __nonzero__(self):
"""This allows us to do tests like if entry: returns false if there is no data,
diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py
index f388f3f4f..fe48a1ffa 100644
--- a/ipa-server/xmlrpc-server/funcs.py
+++ b/ipa-server/xmlrpc-server/funcs.py
@@ -90,42 +90,27 @@ class IPAServer:
filter = "(krbPrincipalName=" + princ + ")"
# The only anonymous search we should have
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,None)
- ent = m1.getEntry(self.basedn, self.scope, filter, ['dn'])
- _LDAPPool.releaseConn(m1)
+ try:
+ ent = m1.getEntry(self.basedn, self.scope, filter, ['dn'])
+ finally:
+ _LDAPPool.releaseConn(m1)
return "dn:" + ent.dn
def convert_entry(self, ent):
-
- # Convert to LDIF
- entry = str(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
- # Strip off any junk
- entry = entry.strip()
- # Don't need to identify binary fields and this breaks the parser so
- # remove double colons
- entry = entry.replace('::', ':')
- specs = [spec.split(':') for spec in entry.split('\n')]
-
- # Convert into a dict. We need to handle multi-valued attributes as well
- # so we'll convert those into lists.
- obj={}
- for (k,v) in specs:
- k = k.lower()
- if obj.get(k) is not None:
- if isinstance(obj[k],list):
- obj[k].append(v.strip())
- else:
- first = obj[k]
- obj[k] = []
- obj[k].append(first)
- obj[k].append(v.strip())
- else:
- obj[k] = v.strip()
-
- return obj
-
def __get_entry (self, base, filter, sattrs=None, opts=None):
"""Get a specific entry. Return as a dict of values.
Multi-valued fields are represented as lists.
@@ -139,8 +124,10 @@ class IPAServer:
dn = self.get_dn_from_principal(self.princ)
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
- ent = m1.getEntry(base, self.scope, filter, sattrs)
- _LDAPPool.releaseConn(m1)
+ try:
+ ent = m1.getEntry(base, self.scope, filter, sattrs)
+ finally:
+ _LDAPPool.releaseConn(m1)
return self.convert_entry(ent)
@@ -169,8 +156,10 @@ class IPAServer:
proxydn = self.get_dn_from_principal(self.princ)
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,proxydn)
- res = m1.updateEntry(moddn, oldentry, newentry)
- _LDAPPool.releaseConn(m1)
+ try:
+ res = m1.updateEntry(moddn, oldentry, newentry)
+ finally:
+ _LDAPPool.releaseConn(m1)
return res
def __safe_filter(self, criteria):
@@ -181,9 +170,34 @@ class IPAServer:
# where the second byte in a multi-byte character
# is (illegally) ')' and make sure python-ldap
# bombs out.
- criteria = re.sub(r'[\(\)\\]', ldap_search_escape, criteria)
+ criteria = re.sub(r'[\(\)\\\*]', ldap_search_escape, criteria)
return criteria
+
+ def __generate_match_filters(self, search_fields, criteria_words):
+ """Generates a search filter based on a list of words and a list
+ of fields to search against.
+
+ Returns a tuple of two filters: (exact_match, partial_match)"""
+
+ # construct search pattern for a single word
+ # (|(f1=word)(f2=word)...)
+ search_pattern = "(|"
+ for field in search_fields:
+ search_pattern += "(" + field + "=%(match)s)"
+ search_pattern += ")"
+ gen_search_pattern = lambda word: search_pattern % {'match':word}
+
+ # construct the giant match for all words
+ exact_match_filter = "(&"
+ partial_match_filter = "(&"
+ for word in criteria_words:
+ exact_match_filter += gen_search_pattern(word)
+ partial_match_filter += gen_search_pattern("*%s*" % word)
+ exact_match_filter += ")"
+ partial_match_filter += ")"
+
+ return (exact_match_filter, partial_match_filter)
# User support
@@ -192,11 +206,10 @@ class IPAServer:
uid = self.__safe_filter(uid)
filter = "(&(uid=%s)(objectclass=posixAccount))" % uid
- entry = self.__get_entry(self.basedn, filter, ['dn','uid'], opts)
-
- if entry is not None:
+ try:
+ entry = self.__get_entry(self.basedn, filter, ['dn','uid'], opts)
return 0
- else:
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
return 1
def get_user_by_uid (self, uid, sattrs=None, opts=None):
@@ -283,8 +296,10 @@ class IPAServer:
dn = self.get_dn_from_principal(self.princ)
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
- res = m1.addEntry(entry)
- _LDAPPool.releaseConn(m1)
+ try:
+ res = m1.addEntry(entry)
+ finally:
+ _LDAPPool.releaseConn(m1)
return res
def get_add_schema (self):
@@ -345,8 +360,10 @@ class IPAServer:
filter = "(objectclass=posixAccount)"
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
- all_users = m1.getList(self.basedn, self.scope, filter, None)
- _LDAPPool.releaseConn(m1)
+ try:
+ all_users = m1.getList(self.basedn, self.scope, filter, None)
+ finally:
+ _LDAPPool.releaseConn(m1)
users = []
for u in all_users:
@@ -365,20 +382,46 @@ class IPAServer:
dn = self.get_dn_from_principal(self.princ)
+ # Assume the list of fields to search will come from a central
+ # configuration repository. A good format for that would be
+ # a comma-separated list of fields
+ search_fields_conf_str = "uid,givenName,sn,telephoneNumber"
+ search_fields = string.split(search_fields_conf_str, ",")
+
criteria = self.__safe_filter(criteria)
+ criteria_words = re.split(r'\s+', criteria)
+ criteria_words = filter(lambda value:value!="", criteria_words)
+ if len(criteria_words) == 0:
+ return []
- filter = "(|(uid=%s)(cn=%s))" % (criteria, criteria)
+ (exact_match_filter, partial_match_filter) = self.__generate_match_filters(
+ search_fields, criteria_words)
+
+ m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
try:
- m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
- results = m1.getList(self.basedn, self.scope, filter, sattrs)
+ try:
+ exact_results = m1.getList(self.basedn, self.scope,
+ exact_match_filter, sattrs)
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ exact_results = []
+
+ try:
+ partial_results = m1.getList(self.basedn, self.scope,
+ partial_match_filter, sattrs)
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ partial_results = []
+ finally:
_LDAPPool.releaseConn(m1)
- except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
- results = []
+
+ # Remove exact matches from the partial_match list
+ exact_dns = set(map(lambda e: e.dn, exact_results))
+ partial_results = filter(lambda e: e.dn not in exact_dns,
+ partial_results)
users = []
- for u in results:
+ for u in exact_results + partial_results:
users.append(self.convert_entry(u))
-
+
return users
def convert_scalar_values(self, orig_dict):
@@ -417,8 +460,10 @@ class IPAServer:
has_key = False
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,proxydn)
- res = m1.inactivateEntry(user['dn'], has_key)
- _LDAPPool.releaseConn(m1)
+ try:
+ res = m1.inactivateEntry(user['dn'], has_key)
+ finally:
+ _LDAPPool.releaseConn(m1)
return res
# Group support
@@ -485,8 +530,10 @@ class IPAServer:
dn = self.get_dn_from_principal(self.princ)
m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
- res = m1.addEntry(entry)
- _LDAPPool.releaseConn(m1)
+ try:
+ res = m1.addEntry(entry)
+ finally:
+ _LDAPPool.releaseConn(m1)
def find_groups (self, criteria, sattrs=None, opts=None):
"""Return a list containing a User object for each
@@ -502,12 +549,13 @@ class IPAServer:
criteria = self.__safe_filter(criteria)
filter = "(&(cn=%s)(objectClass=posixGroup))" % criteria
+ m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
try:
- m1 = _LDAPPool.getConn(self.host,self.port,self.bindca,self.bindcert,self.bindkey,dn)
results = m1.getList(self.basedn, self.scope, filter, sattrs)
- _LDAPPool.releaseConn(m1)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
results = []
+ finally:
+ _LDAPPool.releaseConn(m1)
groups = []
for u in results:
@@ -646,5 +694,8 @@ def ldap_search_escape(match):
return "\\29"
elif value == "\\":
return "\\5c"
+ elif value == "*":
+ # drop '*' from input. search performs its own wildcarding
+ return ""
else:
return value
diff --git a/ipa-server/xmlrpc-server/ipaxmlrpc.py b/ipa-server/xmlrpc-server/ipaxmlrpc.py
index 3f30f8fbd..16ced2cda 100644
--- a/ipa-server/xmlrpc-server/ipaxmlrpc.py
+++ b/ipa-server/xmlrpc-server/ipaxmlrpc.py
@@ -35,7 +35,8 @@ from mod_python import apache
import ipaserver
import funcs
-from ipa import ipaerror
+from ipa import ipaerror, ipautil
+import ldap
import string
import base64
@@ -150,7 +151,12 @@ class ModXMLRPCRequestHandler(object):
response = dumps(response, methodresponse=1, allow_none=1)
except ipaerror.IPAError, e:
self.traceback = True
- response = dumps(Fault(e.code, str(e)))
+
+ if (isinstance(e.detail, ldap.LDAPError)):
+ err = ": %s: %s" % (e.detail.args[0]['desc'], e.detail.args[0].get('info',''))
+ response = dumps(Fault(e.code, str(e) + err))
+ else:
+ response = dumps(Fault(e.code, str(e)))
except:
self.traceback = True
# report exception back to server
@@ -167,14 +173,14 @@ class ModXMLRPCRequestHandler(object):
if func is None:
raise Fault(1, "Invalid method: %s" % method)
- args = list(params)
+ args = list(ipautil.unwrap_binary_data(params))
for i in range(len(args)):
if args[i] == '__NONE__':
args[i] = None
ret = func(*args)
- return ret
+ return ipautil.wrap_binary_data(ret)
def multiCall(self, calls):
"""Execute a multicall. Execute each method call in the calls list, collecting