Skip to content

Commit 94d2133

Browse files
committed
feat(ldap.filter): add is_filter() to verify filter syntax
1 parent 2f0135c commit 94d2133

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

Lib/ldap/filter.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Tested with Python 2.0+
88
"""
99

10+
import _ldap
1011
from ldap import __version__
1112

1213
from ldap.functions import strf_secs
@@ -89,3 +90,27 @@ def time_span_filter(
8990
until_timestr=strf_secs(until_timestamp),
9091
)
9192
# end of time_span_filter()
93+
94+
95+
def is_filter(ldap_filter):
96+
"""
97+
Returns True if `ldap_filter' can be parsed as a valid LDAP filter, otherwise False is returned.
98+
"""
99+
if hasattr(_ldap, 'is_filter'):
100+
return _ldap.is_filter(ldap_filter)
101+
102+
# workaround for libldap <= 2.7
103+
if '\x00' in ldap_filter:
104+
raise ValueError('embedded null character')
105+
import ldap
106+
lo = ldap.initialize('')
107+
try:
108+
lo.search_ext_s('', ldap.SCOPE_BASE, ldap_filter)
109+
except (ldap.FILTER_ERROR, TypeError, ValueError):
110+
return False
111+
except ldap.SERVER_DOWN:
112+
# the filter syntax is valid, as the connection is not bound we expect SERVER_DOWN here
113+
return True
114+
finally:
115+
lo.unbind()
116+
raise RuntimeError('Could not check filter syntax.') # can not happen

Modules/functions.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,31 @@ l_ldap_get_option(PyObject *self, PyObject *args)
399399
return LDAP_get_option(NULL, option);
400400
}
401401

402+
403+
#ifdef HAVE_LDAP_PUT_FILTER
404+
/* ldap_is_filter */
405+
static PyObject *l_ldap_is_filter(PyObject *self, PyObject *args)
406+
{
407+
const char *filter;
408+
if(!PyArg_ParseTuple(args, "s", &filter))
409+
return NULL;
410+
411+
BerElement *ber = ber_alloc_t(LBER_USE_DER);
412+
if(!ber) {
413+
Py_RETURN_FALSE;
414+
}
415+
416+
int rc = ldap_pvt_put_filter(ber, filter);
417+
ber_free(ber, 1);
418+
419+
if (rc == 0) {
420+
Py_RETURN_TRUE;
421+
}
422+
Py_RETURN_FALSE;
423+
}
424+
#endif
425+
426+
402427
/* methods */
403428

404429
static PyMethodDef methods[] = {
@@ -410,6 +435,9 @@ static PyMethodDef methods[] = {
410435
{"dn2str", (PyCFunction)l_ldap_dn2str, METH_VARARGS},
411436
{"set_option", (PyCFunction)l_ldap_set_option, METH_VARARGS},
412437
{"get_option", (PyCFunction)l_ldap_get_option, METH_VARARGS},
438+
#ifdef HAVE_LDAP_PUT_FILTER
439+
{"is_filter", (PyCFunction)l_ldap_is_filter, METH_VARARGS},
440+
#endif
413441
{NULL, NULL}
414442
};
415443

Modules/pythonldap.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ LDAP_F(int) ldap_init_fd(ber_socket_t fd, int proto, LDAP_CONST char *url,
4242
LDAP **ldp);
4343
#endif
4444

45+
#if LDAP_VENDOR_VERSION >= 20700
46+
/* openldap.h made ldap_pvt_put_filter() public in 2.7.x
47+
* see https://bugs.openldap.org/show_bug.cgi?id=9393
48+
*/
49+
#define HAVE_LDAP_PUT_FILTER 1
50+
#endif
51+
4552
#if defined(MS_WINDOWS)
4653
#include <winsock.h>
4754
#else /* unix */

0 commit comments

Comments
 (0)