From 1e20c2d540a201d035debdbfcd61ab96dc6bd8e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Thu, 27 Jan 2022 10:35:56 +0000 Subject: [PATCH 01/41] Check whether libldap is threadsafe on startup. Closes #432 --- Lib/ldap/constants.py | 2 -- Modules/constants.c | 10 ++++++++++ setup.cfg | 6 ++++-- setup.py | 1 - 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Lib/ldap/constants.py b/Lib/ldap/constants.py index 1c1d76a7..f76609b9 100644 --- a/Lib/ldap/constants.py +++ b/Lib/ldap/constants.py @@ -341,9 +341,7 @@ class Str(Constant): # XXX - these should be errors Int('URL_ERR_BADSCOPE'), Int('URL_ERR_MEM'), - # Int('LIBLDAP_R'), - Feature('LIBLDAP_R', 'HAVE_LIBLDAP_R'), Feature('SASL_AVAIL', 'HAVE_SASL'), Feature('TLS_AVAIL', 'HAVE_TLS'), Feature('INIT_FD_AVAIL', 'HAVE_LDAP_INIT_FD'), diff --git a/Modules/constants.c b/Modules/constants.c index 07d60653..8d6f63b0 100644 --- a/Modules/constants.c +++ b/Modules/constants.c @@ -197,6 +197,8 @@ int LDAPinit_constants(PyObject *m) { PyObject *exc, *nobj; + struct ldap_apifeature_info info = { 1, "X_OPENLDAP_THREAD_SAFE", 0 }; + int thread_safe = 0; /* simple constants */ @@ -221,6 +223,14 @@ LDAPinit_constants(PyObject *m) return -1; Py_INCREF(LDAPexception_class); +#ifdef LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE + if (ldap_get_option(NULL, LDAP_OPT_API_FEATURE_INFO, &info) == LDAP_SUCCESS) { + thread_safe = (info.ldapaif_version == 1); + } +#endif + if (PyModule_AddIntConstant(m, "LIBLDAP_R", thread_safe) != 0) + return -1; + /* Generated constants -- see Lib/ldap/constants.py */ #define add_err(n) do { \ diff --git a/setup.cfg b/setup.cfg index 01d43a06..48f36197 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,9 +21,11 @@ defines = HAVE_SASL HAVE_TLS HAVE_LIBLDAP_R extra_compile_args = extra_objects = +# Uncomment this if your libldap is not thread-safe and you need libldap_r +# instead # Example for full-featured build: # Support for StartTLS/LDAPS, SASL bind and reentrant libldap_r. -libs = ldap_r lber +#libs = ldap_r lber # Installation options [install] @@ -33,7 +35,7 @@ optimize = 1 # Linux distributors/packagers should adjust these settings [bdist_rpm] provides = python-ldap -requires = python libldap-2_4 +requires = python libldap-2 vendor = python-ldap project packager = python-ldap team distribution_name = openSUSE 11.x diff --git a/setup.py b/setup.py index 119b5715..b1939571 100644 --- a/setup.py +++ b/setup.py @@ -132,7 +132,6 @@ class OpenLDAP2: extra_objects = LDAP_CLASS.extra_objects, runtime_library_dirs = (not sys.platform.startswith("win"))*LDAP_CLASS.library_dirs, define_macros = LDAP_CLASS.defines + \ - ('ldap_r' in LDAP_CLASS.libs or 'oldap_r' in LDAP_CLASS.libs)*[('HAVE_LIBLDAP_R',None)] + \ ('sasl' in LDAP_CLASS.libs or 'sasl2' in LDAP_CLASS.libs or 'libsasl' in LDAP_CLASS.libs)*[('HAVE_SASL',None)] + \ ('ssl' in LDAP_CLASS.libs and 'crypto' in LDAP_CLASS.libs)*[('HAVE_TLS',None)] + \ [ From 5f8fcfde7797095fe250d58b591edb66d83ad15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Tue, 1 Feb 2022 12:02:53 +0000 Subject: [PATCH 02/41] Regenerate Modules/constants_generated.h --- Modules/constants_generated.h | 43 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/Modules/constants_generated.h b/Modules/constants_generated.h index e357fa23..6070c31d 100644 --- a/Modules/constants_generated.h +++ b/Modules/constants_generated.h @@ -76,10 +76,12 @@ add_err(TOO_LATE); add_err(CANNOT_CANCEL); #endif + #if defined(LDAP_ASSERTION_FAILED) add_err(ASSERTION_FAILED); #endif + #if defined(LDAP_PROXIED_AUTHORIZATION_DENIED) add_err(PROXIED_AUTHORIZATION_DENIED); #endif @@ -192,6 +194,7 @@ add_int(OPT_URI); add_int(OPT_DEFBASE); #endif + #if HAVE_TLS #if defined(LDAP_OPT_X_TLS) @@ -217,18 +220,22 @@ add_int(OPT_X_TLS_TRY); add_int(OPT_X_TLS_VERSION); #endif + #if defined(LDAP_OPT_X_TLS_CIPHER) add_int(OPT_X_TLS_CIPHER); #endif + #if defined(LDAP_OPT_X_TLS_PEERCERT) add_int(OPT_X_TLS_PEERCERT); #endif + #if defined(LDAP_OPT_X_TLS_CRLCHECK) add_int(OPT_X_TLS_CRLCHECK); #endif + #if defined(LDAP_OPT_X_TLS_CRLFILE) add_int(OPT_X_TLS_CRLFILE); #endif @@ -241,14 +248,17 @@ add_int(OPT_X_TLS_CRL_ALL); add_int(OPT_X_TLS_NEWCTX); #endif + #if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) add_int(OPT_X_TLS_PROTOCOL_MIN); #endif + #if defined(LDAP_OPT_X_TLS_PACKAGE) add_int(OPT_X_TLS_PACKAGE); #endif + #if defined(LDAP_OPT_X_TLS_REQUIRE_SAN) add_int(OPT_X_TLS_REQUIRE_SAN); #endif @@ -269,22 +279,27 @@ add_int(OPT_X_SASL_SSF_MAX); add_int(OPT_X_SASL_NOCANON); #endif + #if defined(LDAP_OPT_X_SASL_USERNAME) add_int(OPT_X_SASL_USERNAME); #endif + #if defined(LDAP_OPT_CONNECT_ASYNC) add_int(OPT_CONNECT_ASYNC); #endif + #if defined(LDAP_OPT_X_KEEPALIVE_IDLE) add_int(OPT_X_KEEPALIVE_IDLE); #endif + #if defined(LDAP_OPT_X_KEEPALIVE_PROBES) add_int(OPT_X_KEEPALIVE_PROBES); #endif + #if defined(LDAP_OPT_X_KEEPALIVE_INTERVAL) add_int(OPT_X_KEEPALIVE_INTERVAL); #endif @@ -309,36 +324,24 @@ add_int(OPT_SUCCESS); add_int(URL_ERR_BADSCOPE); add_int(URL_ERR_MEM); -#ifdef HAVE_LIBLDAP_R -if (PyModule_AddIntConstant(m, "LIBLDAP_R", 1) != 0) - return -1; -#else -if (PyModule_AddIntConstant(m, "LIBLDAP_R", 0) != 0) - return -1; -#endif - #ifdef HAVE_SASL -if (PyModule_AddIntConstant(m, "SASL_AVAIL", 1) != 0) - return -1; +if (PyModule_AddIntConstant(m, "SASL_AVAIL", 1) != 0) return -1; #else -if (PyModule_AddIntConstant(m, "SASL_AVAIL", 0) != 0) - return -1; +if (PyModule_AddIntConstant(m, "SASL_AVAIL", 0) != 0) return -1; #endif + #ifdef HAVE_TLS -if (PyModule_AddIntConstant(m, "TLS_AVAIL", 1) != 0) - return -1; +if (PyModule_AddIntConstant(m, "TLS_AVAIL", 1) != 0) return -1; #else -if (PyModule_AddIntConstant(m, "TLS_AVAIL", 0) != 0) - return -1; +if (PyModule_AddIntConstant(m, "TLS_AVAIL", 0) != 0) return -1; #endif + #ifdef HAVE_LDAP_INIT_FD -if (PyModule_AddIntConstant(m, "INIT_FD_AVAIL", 1) != 0) - return -1; +if (PyModule_AddIntConstant(m, "INIT_FD_AVAIL", 1) != 0) return -1; #else -if (PyModule_AddIntConstant(m, "INIT_FD_AVAIL", 0) != 0) - return -1; +if (PyModule_AddIntConstant(m, "INIT_FD_AVAIL", 0) != 0) return -1; #endif add_string(CONTROL_MANAGEDSAIT); From e712033b0ff88463b6ca39d2b02f1779d4bbea16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Tue, 1 Feb 2022 12:03:11 +0000 Subject: [PATCH 03/41] Fix LDAP_VENDOR_VERSION check --- Modules/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/common.h b/Modules/common.h index 886024f2..bc554c85 100644 --- a/Modules/common.h +++ b/Modules/common.h @@ -16,7 +16,7 @@ #include #include -#if LDAP_API_VERSION < 2040 +#if LDAP_VENDOR_VERSION < 20400 #error Current python-ldap requires OpenLDAP 2.4.x #endif From 610b2ee59129a2650414370942dff6dec17d4226 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 16 Sep 2021 13:56:34 +0200 Subject: [PATCH 04/41] Implement support for OPT_X_TLS_PEERCERT Co-authored-by: Thomas Grainger Signed-off-by: Christian Heimes --- Doc/reference/ldap.rst | 7 ++++++- Lib/ldap/constants.py | 3 +++ Modules/berval.c | 2 +- Modules/constants_generated.h | 5 +++++ Modules/options.c | 18 ++++++++++++++++++ Tests/t_ldapobject.py | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Doc/reference/ldap.rst b/Doc/reference/ldap.rst index 57485c7a..def77c66 100644 --- a/Doc/reference/ldap.rst +++ b/Doc/reference/ldap.rst @@ -406,7 +406,12 @@ TLS options .. py:data:: OPT_X_TLS_PEERCERT - Get peer's certificate as binary ASN.1 data structure (not supported) + Get peer's certificate as binary ASN.1 data structure (DER) + + .. versionadded:: 3.4.1 + + .. note:: + The option leaks memory with OpenLDAP < 2.5.8. .. py:data:: OPT_X_TLS_PROTOCOL_MIN diff --git a/Lib/ldap/constants.py b/Lib/ldap/constants.py index f76609b9..19bdd059 100644 --- a/Lib/ldap/constants.py +++ b/Lib/ldap/constants.py @@ -301,6 +301,9 @@ class Str(Constant): # Added in OpenLDAP 2.4.52 TLSInt('OPT_X_TLS_REQUIRE_SAN', optional=True), + # Added in OpenLDAP 2.5 + TLSInt('OPT_X_TLS_PEERCERT', optional=True), + Int('OPT_X_SASL_MECH'), Int('OPT_X_SASL_REALM'), Int('OPT_X_SASL_AUTHCID'), diff --git a/Modules/berval.c b/Modules/berval.c index 7435ee0a..6917baef 100644 --- a/Modules/berval.c +++ b/Modules/berval.c @@ -17,7 +17,7 @@ LDAPberval_to_object(const struct berval *bv) { PyObject *ret = NULL; - if (!bv) { + if (!bv || !bv->bv_val) { ret = Py_None; Py_INCREF(ret); } diff --git a/Modules/constants_generated.h b/Modules/constants_generated.h index 6070c31d..ccb42782 100644 --- a/Modules/constants_generated.h +++ b/Modules/constants_generated.h @@ -263,6 +263,11 @@ add_int(OPT_X_TLS_PACKAGE); add_int(OPT_X_TLS_REQUIRE_SAN); #endif + +#if defined(LDAP_OPT_X_TLS_PEERCERT) +add_int(OPT_X_TLS_PEERCERT); +#endif + #endif add_int(OPT_X_SASL_MECH); diff --git a/Modules/options.c b/Modules/options.c index db5fde3e..af775766 100644 --- a/Modules/options.c +++ b/Modules/options.c @@ -5,6 +5,7 @@ #include "LDAPObject.h" #include "ldapcontrol.h" #include "options.h" +#include "berval.h" void set_timeval_from_double(struct timeval *tv, double d) @@ -58,6 +59,9 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) case LDAP_OPT_API_FEATURE_INFO: #ifdef HAVE_SASL case LDAP_OPT_X_SASL_SSF: +#endif +#ifdef LDAP_OPT_X_TLS_PEERCERT + case LDAP_OPT_X_TLS_PEERCERT: #endif /* Read-only options */ PyErr_SetString(PyExc_ValueError, "read-only option"); @@ -254,6 +258,7 @@ LDAP_get_option(LDAPObject *self, int option) LDAPAPIInfo apiinfo; LDAPControl **lcs; char *strval; + struct berval berbytes; #if HAVE_SASL /* unsigned long */ ber_len_t blen; @@ -406,6 +411,19 @@ LDAP_get_option(LDAPObject *self, int option) ldap_memfree(strval); return v; +#ifdef HAVE_TLS +#ifdef LDAP_OPT_X_TLS_PEERCERT + case LDAP_OPT_X_TLS_PEERCERT: +#endif +#endif + /* Options dealing with raw data */ + res = LDAP_int_get_option(self, option, &berbytes); + if (res != LDAP_OPT_SUCCESS) + return option_error(res, "ldap_get_option"); + v = LDAPberval_to_object(&berbytes); + ldap_memfree(berbytes.bv_val); + return v; + case LDAP_OPT_TIMEOUT: case LDAP_OPT_NETWORK_TIMEOUT: /* Double-valued timeval options */ diff --git a/Tests/t_ldapobject.py b/Tests/t_ldapobject.py index 3bcc00a2..07a78595 100644 --- a/Tests/t_ldapobject.py +++ b/Tests/t_ldapobject.py @@ -20,6 +20,11 @@ from slapdtest import requires_ldapi, requires_sasl, requires_tls from slapdtest import requires_init_fd +try: + from ssl import PEM_cert_to_DER_cert +except ImportError: + PEM_cert_to_DER_cert = None + LDIF_TEMPLATE = """dn: %(suffix)s objectClass: dcObject @@ -421,6 +426,36 @@ def test_multiple_starttls(self): l.simple_bind_s(self.server.root_dn, self.server.root_pw) self.assertEqual(l.whoami_s(), 'dn:' + self.server.root_dn) + @requires_tls() + @unittest.skipUnless( + hasattr(ldap, "OPT_X_TLS_PEERCERT"), + reason="Requires OPT_X_TLS_PEERCERT" + ) + def test_get_tls_peercert(self): + l = self.ldap_object_class(self.server.ldap_uri) + peercert = l.get_option(ldap.OPT_X_TLS_PEERCERT) + self.assertEqual(peercert, None) + with self.assertRaises(ValueError): + l.set_option(ldap.OPT_X_TLS_PEERCERT, b"") + + l.set_option(ldap.OPT_X_TLS_CACERTFILE, self.server.cafile) + l.set_option(ldap.OPT_X_TLS_NEWCTX, 0) + l.start_tls_s() + + peercert = l.get_option(ldap.OPT_X_TLS_PEERCERT) + self.assertTrue(peercert) + self.assertIsInstance(peercert, bytes) + + if PEM_cert_to_DER_cert is not None: + with open(self.server.servercert) as f: + server_pem = f.read() + # remove text + begin = server_pem.find("-----BEGIN CERTIFICATE-----") + server_pem = server_pem[begin:-1] + + server_der = PEM_cert_to_DER_cert(server_pem) + self.assertEqual(server_der, peercert) + def test_dse(self): dse = self._ldap_conn.read_rootdse_s() self.assertIsInstance(dse, dict) From c4efbdabb35acab6be89435ed59608ee439153f9 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 18 Sep 2021 17:36:44 +0200 Subject: [PATCH 05/41] Use regex to locate PEM body --- Tests/t_ldapobject.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Tests/t_ldapobject.py b/Tests/t_ldapobject.py index 07a78595..9e4e3311 100644 --- a/Tests/t_ldapobject.py +++ b/Tests/t_ldapobject.py @@ -3,9 +3,11 @@ See https://www.python-ldap.org/ for details. """ +import base64 import errno import linecache import os +import re import socket import unittest import pickle @@ -20,10 +22,10 @@ from slapdtest import requires_ldapi, requires_sasl, requires_tls from slapdtest import requires_init_fd -try: - from ssl import PEM_cert_to_DER_cert -except ImportError: - PEM_cert_to_DER_cert = None +PEM_CERT_RE = re.compile( + b'-----BEGIN CERTIFICATE-----(.*?)-----END CERTIFICATE-----', + re.DOTALL +) LDIF_TEMPLATE = """dn: %(suffix)s @@ -446,15 +448,12 @@ def test_get_tls_peercert(self): self.assertTrue(peercert) self.assertIsInstance(peercert, bytes) - if PEM_cert_to_DER_cert is not None: - with open(self.server.servercert) as f: - server_pem = f.read() - # remove text - begin = server_pem.find("-----BEGIN CERTIFICATE-----") - server_pem = server_pem[begin:-1] + with open(self.server.servercert, "rb") as f: + server_cert = f.read() + pem_body = PEM_CERT_RE.search(server_cert).group(1) + server_der = base64.b64decode(pem_body) - server_der = PEM_cert_to_DER_cert(server_pem) - self.assertEqual(server_der, peercert) + self.assertEqual(server_der, peercert) def test_dse(self): dse = self._ldap_conn.read_rootdse_s() From dbd7a3847121e24c3a32b10c6a9016129a08ea0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Mon, 14 Feb 2022 13:08:57 +0000 Subject: [PATCH 06/41] Process missing libldap options --- Lib/ldap/constants.py | 3 +++ Modules/constants_generated.h | 11 ++++++++++ Modules/options.c | 40 ++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Lib/ldap/constants.py b/Lib/ldap/constants.py index 19bdd059..71994a8d 100644 --- a/Lib/ldap/constants.py +++ b/Lib/ldap/constants.py @@ -244,6 +244,7 @@ class Str(Constant): Int('OPT_SIZELIMIT'), Int('OPT_TIMELIMIT'), Int('OPT_REFERRALS', optional=True), + Int('OPT_RESULT_CODE'), Int('OPT_ERROR_NUMBER'), Int('OPT_RESTART'), Int('OPT_PROTOCOL_VERSION'), @@ -261,6 +262,7 @@ class Str(Constant): Int('OPT_TIMEOUT'), Int('OPT_REFHOPLIMIT'), Int('OPT_NETWORK_TIMEOUT'), + Int('OPT_TCP_USER_TIMEOUT', optional=True), Int('OPT_URI'), Int('OPT_DEFBASE', optional=True), @@ -299,6 +301,7 @@ class Str(Constant): TLSInt('OPT_X_TLS_PACKAGE', optional=True), # Added in OpenLDAP 2.4.52 + TLSInt('OPT_X_TLS_ECNAME', optional=True), TLSInt('OPT_X_TLS_REQUIRE_SAN', optional=True), # Added in OpenLDAP 2.5 diff --git a/Modules/constants_generated.h b/Modules/constants_generated.h index ccb42782..9df264ed 100644 --- a/Modules/constants_generated.h +++ b/Modules/constants_generated.h @@ -173,6 +173,7 @@ add_int(OPT_TIMELIMIT); add_int(OPT_REFERRALS); #endif +add_int(OPT_RESULT_CODE); add_int(OPT_ERROR_NUMBER); add_int(OPT_RESTART); add_int(OPT_PROTOCOL_VERSION); @@ -188,6 +189,11 @@ add_int(OPT_DEBUG_LEVEL); add_int(OPT_TIMEOUT); add_int(OPT_REFHOPLIMIT); add_int(OPT_NETWORK_TIMEOUT); + +#if defined(LDAP_OPT_TCP_USER_TIMEOUT) +add_int(OPT_TCP_USER_TIMEOUT); +#endif + add_int(OPT_URI); #if defined(LDAP_OPT_DEFBASE) @@ -259,6 +265,11 @@ add_int(OPT_X_TLS_PACKAGE); #endif +#if defined(LDAP_OPT_X_TLS_ECNAME) +add_int(OPT_X_TLS_ECNAME); +#endif + + #if defined(LDAP_OPT_X_TLS_REQUIRE_SAN) add_int(OPT_X_TLS_REQUIRE_SAN); #endif diff --git a/Modules/options.c b/Modules/options.c index af775766..ef9eddf2 100644 --- a/Modules/options.c +++ b/Modules/options.c @@ -41,6 +41,7 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) { int res; int intval; + unsigned int uintval; double doubleval; char *strval; struct timeval tv; @@ -57,6 +58,7 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) switch (option) { case LDAP_OPT_API_INFO: case LDAP_OPT_API_FEATURE_INFO: + case LDAP_OPT_DESC: #ifdef HAVE_SASL case LDAP_OPT_X_SASL_SSF: #endif @@ -116,10 +118,19 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) ptr = &intval; break; +#ifdef LDAP_OPT_TCP_USER_TIMEOUT + case LDAP_OPT_TCP_USER_TIMEOUT: +#endif + if (!PyArg_Parse(value, "I:set_option", &uintval)) + return 0; + ptr = &uintval; + break; + #ifdef HAVE_SASL case LDAP_OPT_X_SASL_SSF_MIN: case LDAP_OPT_X_SASL_SSF_MAX: case LDAP_OPT_X_SASL_SSF_EXTERNAL: + case LDAP_OPT_X_SASL_MAXBUFSIZE: if (!PyArg_Parse(value, "k:set_option", &blen)) return 0; ptr = &blen; @@ -144,9 +155,15 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) #ifdef LDAP_OPT_X_TLS_CRLFILE case LDAP_OPT_X_TLS_CRLFILE: #endif +#ifdef LDAP_OPT_X_TLS_ECNAME + case LDAP_OPT_X_TLS_ECNAME: +#endif #endif #ifdef HAVE_SASL case LDAP_OPT_X_SASL_SECPROPS: +#endif +#ifdef LDAP_OPT_SOCKET_BIND_ADDRESSES + case LDAP_OPT_SOCKET_BIND_ADDRESSES: #endif /* String valued options */ if (!PyArg_Parse(value, "s:set_option", &strval)) @@ -187,8 +204,8 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) } else { PyErr_Format(PyExc_ValueError, - "timeout must be >= 0 or -1/None for infinity, got %d", - option); + "timeout must be >= 0 or -1/None for infinity, got %f", + doubleval); return 0; } break; @@ -254,6 +271,7 @@ LDAP_get_option(LDAPObject *self, int option) { int res; int intval; + unsigned int uintval; struct timeval *tv; LDAPAPIInfo apiinfo; LDAPControl **lcs; @@ -268,6 +286,7 @@ LDAP_get_option(LDAPObject *self, int option) switch (option) { #ifdef HAVE_SASL + case LDAP_OPT_X_SASL_SECPROPS: case LDAP_OPT_X_SASL_SSF_EXTERNAL: /* Write-only options */ PyErr_SetString(PyExc_ValueError, "write-only option"); @@ -350,10 +369,20 @@ LDAP_get_option(LDAPObject *self, int option) return option_error(res, "ldap_get_option"); return PyInt_FromLong(intval); +#ifdef LDAP_OPT_TCP_USER_TIMEOUT + case LDAP_OPT_TCP_USER_TIMEOUT: +#endif + /* unsigned int options */ + res = LDAP_int_get_option(self, option, &uintval); + if (res != LDAP_OPT_SUCCESS) + return option_error(res, "ldap_get_option"); + return PyLong_FromUnsignedLong(uintval); + #ifdef HAVE_SASL case LDAP_OPT_X_SASL_SSF: case LDAP_OPT_X_SASL_SSF_MIN: case LDAP_OPT_X_SASL_SSF_MAX: + case LDAP_OPT_X_SASL_MAXBUFSIZE: /* ber_len_t options (unsigned long)*/ res = LDAP_int_get_option(self, option, &blen); if (res != LDAP_OPT_SUCCESS) @@ -388,9 +417,11 @@ LDAP_get_option(LDAPObject *self, int option) #ifdef LDAP_OPT_X_TLS_PACKAGE case LDAP_OPT_X_TLS_PACKAGE: #endif +#ifdef LDAP_OPT_X_TLS_ECNAME + case LDAP_OPT_X_TLS_ECNAME: +#endif #endif #ifdef HAVE_SASL - case LDAP_OPT_X_SASL_SECPROPS: case LDAP_OPT_X_SASL_MECH: case LDAP_OPT_X_SASL_REALM: case LDAP_OPT_X_SASL_AUTHCID: @@ -398,6 +429,9 @@ LDAP_get_option(LDAPObject *self, int option) #ifdef LDAP_OPT_X_SASL_USERNAME case LDAP_OPT_X_SASL_USERNAME: #endif +#endif +#ifdef LDAP_OPT_SOCKET_BIND_ADDRESSES + case LDAP_OPT_SOCKET_BIND_ADDRESSES: #endif /* String-valued options */ res = LDAP_int_get_option(self, option, &strval); From 6462e58a68bbf674eeace5f6ac035b51966db7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Mon, 14 Feb 2022 15:08:08 +0000 Subject: [PATCH 07/41] In liblber {0, ""} corresponds to b'' and {0, NULL} corresponds to None --- Tests/t_ldap_options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/t_ldap_options.py b/Tests/t_ldap_options.py index 89f21a43..e9bef591 100644 --- a/Tests/t_ldap_options.py +++ b/Tests/t_ldap_options.py @@ -23,8 +23,8 @@ ]) TEST_CTRL_EXPECTED = [ TEST_CTRL[0], - # get_option returns empty bytes - (TEST_CTRL[1][0], TEST_CTRL[1][1], b''), + # Noop has no value + (TEST_CTRL[1][0], TEST_CTRL[1][1], None), ] From 5cac85a7afeaf117d4b449e9e706a2679accc8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 6 Apr 2022 11:42:43 +0100 Subject: [PATCH 08/41] Add TLS version numbers and remove unsupported TLS options Closes #67 --- Doc/reference/ldap.rst | 64 +++++++++++++++++++++++++---------- Lib/ldap/constants.py | 9 +++-- Modules/constants_generated.h | 36 ++++++++++++++++---- Modules/options.c | 6 ++++ 4 files changed, 90 insertions(+), 25 deletions(-) diff --git a/Doc/reference/ldap.rst b/Doc/reference/ldap.rst index def77c66..9bd6b142 100644 --- a/Doc/reference/ldap.rst +++ b/Doc/reference/ldap.rst @@ -372,21 +372,27 @@ TLS options .. py:data:: OPT_X_TLS_ALLOW Value for :py:const:`OPT_X_TLS_REQUIRE_CERT` + and :py:const:`OPT_X_TLS_REQUIRE_SAN` .. py:data:: OPT_X_TLS_DEMAND Value for :py:const:`OPT_X_TLS_REQUIRE_CERT` + and :py:const:`OPT_X_TLS_REQUIRE_SAN` .. py:data:: OPT_X_TLS_HARD Value for :py:const:`OPT_X_TLS_REQUIRE_CERT` + and :py:const:`OPT_X_TLS_REQUIRE_SAN` .. py:data:: OPT_X_TLS_NEVER Value for :py:const:`OPT_X_TLS_REQUIRE_CERT` + and :py:const:`OPT_X_TLS_REQUIRE_SAN` .. py:data:: OPT_X_TLS_TRY + Value for :py:const:`OPT_X_TLS_REQUIRE_CERT` + .. deprecated:: 3.3.0 This value is only used by slapd server internally. It will be removed in the future. @@ -400,10 +406,6 @@ TLS options get/set allowed cipher suites -.. py:data:: OPT_X_TLS_CTX - - get address of internal memory address of TLS context (**DO NOT USE**) - .. py:data:: OPT_X_TLS_PEERCERT Get peer's certificate as binary ASN.1 data structure (DER) @@ -417,8 +419,47 @@ TLS options get/set minimum protocol version (wire protocol version as int) - * ``0x303`` for TLS 1.2 - * ``0x304`` for TLS 1.3 +.. py:data:: OPT_X_TLS_PROTOCOL_MAX + + get/set maximum protocol version (wire protocol version as int), + available in OpenSSL 2.5 and newer. + + .. versionadded:: 3.4.1 + +.. py:data:: OPT_X_TLS_PROTOCOL_SSL3 + + Value for :py:const:`OPT_X_TLS_PROTOCOL_MIN` and + :py:const:`OPT_X_TLS_PROTOCOL_MAX`, represents SSL 3 + + .. versionadded:: 3.4.1 + +.. py:data:: OPT_X_TLS_PROTOCOL_TLS1_0 + + Value for :py:const:`OPT_X_TLS_PROTOCOL_MIN` and + :py:const:`OPT_X_TLS_PROTOCOL_MAX`, represents TLS 1.0 + + .. versionadded:: 3.4.1 + +.. py:data:: OPT_X_TLS_PROTOCOL_TLS1_1 + + Value for :py:const:`OPT_X_TLS_PROTOCOL_MIN` and + :py:const:`OPT_X_TLS_PROTOCOL_MAX`, represents TLS 1.1 + + .. versionadded:: 3.4.1 + +.. py:data:: OPT_X_TLS_PROTOCOL_TLS1_2 + + Value for :py:const:`OPT_X_TLS_PROTOCOL_MIN` and + :py:const:`OPT_X_TLS_PROTOCOL_MAX`, represents TLS 1.2 + + .. versionadded:: 3.4.1 + +.. py:data:: OPT_X_TLS_PROTOCOL_TLS1_3 + + Value for :py:const:`OPT_X_TLS_PROTOCOL_MIN` and + :py:const:`OPT_X_TLS_PROTOCOL_MAX`, represents TLS 1.3 + + .. versionadded:: 3.4.1 .. py:data:: OPT_X_TLS_VERSION @@ -428,12 +469,6 @@ TLS options get/set path to /dev/urandom (**DO NOT USE**) -.. py:data:: OPT_X_TLS - - .. deprecated:: 3.3.0 - The option is deprecated in OpenLDAP and should no longer be used. It - will be removed in the future. - .. note:: OpenLDAP supports several TLS/SSL libraries. OpenSSL is the most common @@ -923,11 +958,6 @@ and wait for and return with the server's result, or with The *dn* and *attr* arguments are text strings; see :ref:`bytes_mode`. - .. note:: - - A design fault in the LDAP API prevents *value* - from containing *NULL* characters. - .. py:method:: LDAPObject.delete(dn) -> int diff --git a/Lib/ldap/constants.py b/Lib/ldap/constants.py index 71994a8d..1807fc55 100644 --- a/Lib/ldap/constants.py +++ b/Lib/ldap/constants.py @@ -267,8 +267,6 @@ class Str(Constant): Int('OPT_DEFBASE', optional=True), - TLSInt('OPT_X_TLS', optional=True), - TLSInt('OPT_X_TLS_CTX'), TLSInt('OPT_X_TLS_CACERTFILE'), TLSInt('OPT_X_TLS_CACERTDIR'), TLSInt('OPT_X_TLS_CERTFILE'), @@ -306,6 +304,13 @@ class Str(Constant): # Added in OpenLDAP 2.5 TLSInt('OPT_X_TLS_PEERCERT', optional=True), + TLSInt('OPT_X_TLS_PROTOCOL_MAX', optional=True), + + TLSInt('OPT_X_TLS_PROTOCOL_SSL3', optional=True), + TLSInt('OPT_X_TLS_PROTOCOL_TLS1_0', optional=True), + TLSInt('OPT_X_TLS_PROTOCOL_TLS1_1', optional=True), + TLSInt('OPT_X_TLS_PROTOCOL_TLS1_2', optional=True), + TLSInt('OPT_X_TLS_PROTOCOL_TLS1_3', optional=True), Int('OPT_X_SASL_MECH'), Int('OPT_X_SASL_REALM'), diff --git a/Modules/constants_generated.h b/Modules/constants_generated.h index 9df264ed..2d385549 100644 --- a/Modules/constants_generated.h +++ b/Modules/constants_generated.h @@ -202,12 +202,6 @@ add_int(OPT_DEFBASE); #if HAVE_TLS - -#if defined(LDAP_OPT_X_TLS) -add_int(OPT_X_TLS); -#endif - -add_int(OPT_X_TLS_CTX); add_int(OPT_X_TLS_CACERTFILE); add_int(OPT_X_TLS_CACERTDIR); add_int(OPT_X_TLS_CERTFILE); @@ -279,6 +273,36 @@ add_int(OPT_X_TLS_REQUIRE_SAN); add_int(OPT_X_TLS_PEERCERT); #endif + +#if defined(LDAP_OPT_X_TLS_PROTOCOL_MAX) +add_int(OPT_X_TLS_PROTOCOL_MAX); +#endif + + +#if defined(LDAP_OPT_X_TLS_PROTOCOL_SSL3) +add_int(OPT_X_TLS_PROTOCOL_SSL3); +#endif + + +#if defined(LDAP_OPT_X_TLS_PROTOCOL_TLS1_0) +add_int(OPT_X_TLS_PROTOCOL_TLS1_0); +#endif + + +#if defined(LDAP_OPT_X_TLS_PROTOCOL_TLS1_1) +add_int(OPT_X_TLS_PROTOCOL_TLS1_1); +#endif + + +#if defined(LDAP_OPT_X_TLS_PROTOCOL_TLS1_2) +add_int(OPT_X_TLS_PROTOCOL_TLS1_2); +#endif + + +#if defined(LDAP_OPT_X_TLS_PROTOCOL_TLS1_3) +add_int(OPT_X_TLS_PROTOCOL_TLS1_3); +#endif + #endif add_int(OPT_X_SASL_MECH); diff --git a/Modules/options.c b/Modules/options.c index ef9eddf2..1a22bed1 100644 --- a/Modules/options.c +++ b/Modules/options.c @@ -98,6 +98,9 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN case LDAP_OPT_X_TLS_PROTOCOL_MIN: #endif +#ifdef LDAP_OPT_X_TLS_PROTOCOL_MAX + case LDAP_OPT_X_TLS_PROTOCOL_MAX: +#endif #ifdef LDAP_OPT_X_TLS_REQUIRE_SAN case LDAP_OPT_X_TLS_REQUIRE_SAN: #endif @@ -344,6 +347,9 @@ LDAP_get_option(LDAPObject *self, int option) #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN case LDAP_OPT_X_TLS_PROTOCOL_MIN: #endif +#ifdef LDAP_OPT_X_TLS_PROTOCOL_MAX + case LDAP_OPT_X_TLS_PROTOCOL_MAX: +#endif #ifdef LDAP_OPT_X_TLS_REQUIRE_SAN case LDAP_OPT_X_TLS_REQUIRE_SAN: #endif From febaf561b241a0d0cbe8be6ea5f786f4276c30ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Thu, 27 Jan 2022 10:35:56 +0000 Subject: [PATCH 09/41] Fix omissions from previous merge. --- Doc/reference/ldap.rst | 4 ++-- setup.cfg | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/reference/ldap.rst b/Doc/reference/ldap.rst index 9bd6b142..5d4fb642 100644 --- a/Doc/reference/ldap.rst +++ b/Doc/reference/ldap.rst @@ -349,7 +349,7 @@ TLS options .. py:data:: OPT_X_TLS_REQUIRE_SAN get/set how OpenLDAP validates subject alternative name extension, - available in OpenSSL 2.4.52 and newer. + available in OpenLDAP 2.4.52 and newer. :py:const:`OPT_X_TLS_NEVER` Don't check SAN @@ -422,7 +422,7 @@ TLS options .. py:data:: OPT_X_TLS_PROTOCOL_MAX get/set maximum protocol version (wire protocol version as int), - available in OpenSSL 2.5 and newer. + available in OpenLDAP 2.5 and newer. .. versionadded:: 3.4.1 diff --git a/setup.cfg b/setup.cfg index 48f36197..fdb32fbc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,7 +16,7 @@ license_file = LICENCE # These defines needs OpenLDAP built with # ./configure --with-cyrus-sasl --with-tls -defines = HAVE_SASL HAVE_TLS HAVE_LIBLDAP_R +defines = HAVE_SASL HAVE_TLS extra_compile_args = extra_objects = From 8666af380ef8dde9973f46fb20e458f7eab6ce9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 6 Apr 2022 11:11:08 +0100 Subject: [PATCH 10/41] Update to behera ppolicy draft 11 --- Lib/ldap/controls/ppolicy.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/ldap/controls/ppolicy.py b/Lib/ldap/controls/ppolicy.py index da7586f0..f3a8416d 100644 --- a/Lib/ldap/controls/ppolicy.py +++ b/Lib/ldap/controls/ppolicy.py @@ -40,9 +40,10 @@ class PasswordPolicyError(univ.Enumerated): ('insufficientPasswordQuality',5), ('passwordTooShort',6), ('passwordTooYoung',7), - ('passwordInHistory',8) + ('passwordInHistory',8), + ('passwordTooLong',9), ) - subtypeSpec = univ.Enumerated.subtypeSpec + constraint.SingleValueConstraint(0,1,2,3,4,5,6,7,8) + subtypeSpec = univ.Enumerated.subtypeSpec + constraint.SingleValueConstraint(0,1,2,3,4,5,6,7,8,9) class PasswordPolicyResponseValue(univ.Sequence): From 7c25278259952e4787e86d20934af71fc17c197d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 20 Apr 2022 15:38:51 +0100 Subject: [PATCH 11/41] Make 'method' parameter of ReconnectLDAPObject._store_last_bind private Fixes: https://github.com/python-ldap/python-ldap/issues/448 --- Lib/ldap/ldapobject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index 40091ad7..9442e39b 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -895,8 +895,8 @@ def __setstate__(self,d): self._trace_file = ldap._trace_file self.reconnect(self._uri) - def _store_last_bind(self,method,*args,**kwargs): - self._last_bind = (method,args,kwargs) + def _store_last_bind(self,_method,*args,**kwargs): + self._last_bind = (_method,args,kwargs) def _apply_last_bind(self): if self._last_bind!=None: From 7f30c4721ea2ca4373ed7860e6467781f0afa758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 20 Apr 2022 14:42:42 +0100 Subject: [PATCH 12/41] Document OPT_X_SASL_* differ from others Fixes: https://github.com/python-ldap/python-ldap/issues/468 --- Doc/reference/ldap.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Doc/reference/ldap.rst b/Doc/reference/ldap.rst index 5d4fb642..0046f4a1 100644 --- a/Doc/reference/ldap.rst +++ b/Doc/reference/ldap.rst @@ -226,6 +226,9 @@ the following option identifiers are defined as constants: SASL options :::::::::::: +Unlike most other options, SASL options must be set on an +:py:class:`LDAPObject` instance. + .. py:data:: OPT_X_SASL_AUTHCID .. py:data:: OPT_X_SASL_AUTHZID @@ -234,7 +237,8 @@ SASL options .. py:data:: OPT_X_SASL_NOCANON - If set to zero SASL host name canonicalization is disabled. + If set to zero, SASL host name canonicalization is disabled. This is the only + SASL option that can be set globally. .. py:data:: OPT_X_SASL_REALM From 81e1f28c15c86ddc48eddca39fdf64273809587d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 1 Jun 2022 09:39:55 +0100 Subject: [PATCH 13/41] Correct SASL option documentation --- Doc/reference/ldap.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/reference/ldap.rst b/Doc/reference/ldap.rst index 0046f4a1..2d5c4780 100644 --- a/Doc/reference/ldap.rst +++ b/Doc/reference/ldap.rst @@ -237,8 +237,7 @@ Unlike most other options, SASL options must be set on an .. py:data:: OPT_X_SASL_NOCANON - If set to zero, SASL host name canonicalization is disabled. This is the only - SASL option that can be set globally. + If set to zero, SASL host name canonicalization is disabled. .. py:data:: OPT_X_SASL_REALM From 59af061d1bc2fad832952f0b18105ab1ae18246d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 1 Jun 2022 10:53:14 +0100 Subject: [PATCH 14/41] Prepare CHANGELOG --- CHANGES | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CHANGES b/CHANGES index c358fa9e..8f9237a8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,43 @@ +Released 3.4.1 2022-07-05 + +This is a minor release to provide out-of-the-box compatibility with the merge +of libldap and libldap_r that happened with OpenLDAP's 2.5 release. + +The following undocumented functions are deprecated and scheduled for removal: +- ``ldap.cidict.strlist_intersection`` +- ``ldap.cidict.strlist_minus`` +- ``ldap.cidict.strlist_union`` + +The following deprecated option has been removed: +- ``OPT_X_TLS`` + +Doc/ +* SASL option usage has been clarified + +Lib/ +* ppolicy control definition has been updated to match Behera draft 11 + +Modules/ +* By default, compile against libldap, checking whether it provides a + threadsafe implementation at runtime +* When decoding controls, the module can now distinguish between no value + (now exposed as ``None``) and an empty value (exposed as ``b''``) +* Several new OpenLDAP options are now supported: + * ``OPT_SOCKET_BIND_ADDRESSES`` + * ``OPT_TCP_USER_TIMEOUT`` + * ``OPT_X_SASL_MAXBUFSIZE`` + * ``OPT_X_SASL_SECPROPS`` + * ``OPT_X_TLS_ECNAME`` + * ``OPT_X_TLS_PEERCERT`` + * ``OPT_X_TLS_PROTOCOL``-related options and constants + +Fixes: +* Encoding/decoding of boolean controls has been corrected +* ldap.schema.models.Entry is now usable +* ``method`` keyword to ReconnectLDAPObject.bind_s is now usable + + +---------------------------------------------------------------- Released 3.4.0 2021-11-26 This release requires Python 3.6 or above, From b80e8135785ef80a40a52eb61033a54dfd70266e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Tue, 5 Jul 2022 15:29:24 +0100 Subject: [PATCH 15/41] Prepare a new release --- CHANGES | 2 +- Doc/contributing.rst | 2 ++ Lib/ldap/pkginfo.py | 2 +- Lib/ldapurl.py | 2 +- Lib/ldif.py | 2 +- Lib/slapdtest/__init__.py | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 8f9237a8..b1ccc990 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -Released 3.4.1 2022-07-05 +Released 3.4.2 2022-07-06 This is a minor release to provide out-of-the-box compatibility with the merge of libldap and libldap_r that happened with OpenLDAP's 2.5 release. diff --git a/Doc/contributing.rst b/Doc/contributing.rst index 1fc1365b..bbaab491 100644 --- a/Doc/contributing.rst +++ b/Doc/contributing.rst @@ -218,6 +218,8 @@ If you are tasked with releasing python-ldap, remember to: * Go through all changes since last version, and add them to ``CHANGES``. * Run :ref:`additional tests` as appropriate, fix any regressions. * Change the release date in ``CHANGES``. +* Update ``__version__`` tags where appropriate (each module ``ldap``, + ``ldif``, ``ldapurl``, ``slapdtest`` has its own copy). * Merge all that (using pull requests). * Run ``python setup.py sdist``, and smoke-test the resulting package (install in a clean virtual environment, import ``ldap``). diff --git a/Lib/ldap/pkginfo.py b/Lib/ldap/pkginfo.py index ef958a13..4e195264 100644 --- a/Lib/ldap/pkginfo.py +++ b/Lib/ldap/pkginfo.py @@ -1,6 +1,6 @@ """ meta attributes for packaging which does not import any dependencies """ -__version__ = '3.4.0' +__version__ = '3.4.2' __author__ = 'python-ldap project' __license__ = 'Python style' diff --git a/Lib/ldapurl.py b/Lib/ldapurl.py index cce4e806..e76528a7 100644 --- a/Lib/ldapurl.py +++ b/Lib/ldapurl.py @@ -4,7 +4,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.0' +__version__ = '3.4.2' __all__ = [ # constants diff --git a/Lib/ldif.py b/Lib/ldif.py index 7e69a594..7561d09a 100644 --- a/Lib/ldif.py +++ b/Lib/ldif.py @@ -3,7 +3,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.0' +__version__ = '3.4.2' __all__ = [ # constants diff --git a/Lib/slapdtest/__init__.py b/Lib/slapdtest/__init__.py index bb59e7fa..a49b13f7 100644 --- a/Lib/slapdtest/__init__.py +++ b/Lib/slapdtest/__init__.py @@ -4,7 +4,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.0' +__version__ = '3.4.2' from slapdtest._slapdtest import SlapdObject, SlapdTestCase, SysLogHandler from slapdtest._slapdtest import requires_ldapi, requires_sasl, requires_tls From 00eaedd09ce5a7dabb4bc337443e020771177fa4 Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Fri, 26 Aug 2022 23:03:38 +0200 Subject: [PATCH 16/41] Add ASN.1 replace to psearch control Allow Sphinx to pickup the ASN.1 substitution from pyasn1, so docs can build. --- Doc/reference/ldap-controls.rst | 1 + Doc/reference/ldap-extop.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Doc/reference/ldap-controls.rst b/Doc/reference/ldap-controls.rst index 37d7c1bc..2206e101 100644 --- a/Doc/reference/ldap-controls.rst +++ b/Doc/reference/ldap-controls.rst @@ -171,6 +171,7 @@ search. .. autoclass:: ldap.controls.psearch.EntryChangeNotificationControl :members: +.. |ASN.1| replace:: Asn1Type :py:mod:`ldap.controls.sessiontrack` Session tracking control ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Doc/reference/ldap-extop.rst b/Doc/reference/ldap-extop.rst index 8fe49f42..ad70e4e7 100644 --- a/Doc/reference/ldap-extop.rst +++ b/Doc/reference/ldap-extop.rst @@ -38,3 +38,5 @@ This requires :py:mod:`pyasn1` and :py:mod:`pyasn1_modules` to be installed. .. autoclass:: ldap.extop.dds.RefreshResponse :members: + +.. |ASN.1| replace:: Asn1Type From e5959b38902bbf1d68a3f16b04ddc210884b8d5e Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Sat, 27 Aug 2022 19:40:46 +0200 Subject: [PATCH 17/41] Fix broken reset and tearDown in pypy3 There appear to be some minor differences in the CPython and Pypy3 implementations of del. Use delattr to ensure that hasattr will see the attributes as deleted. --- Tests/t_ldapobject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/t_ldapobject.py b/Tests/t_ldapobject.py index 9e4e3311..ccc7d218 100644 --- a/Tests/t_ldapobject.py +++ b/Tests/t_ldapobject.py @@ -658,12 +658,12 @@ def _open_ldap_conn(self, who=None, cred=None, **kwargs): def tearDown(self): self._sock.close() - del self._sock + delattr(self, '_sock') super().tearDown() def reset_connection(self): self._sock.close() - del self._sock + delattr(self, '_sock') super(Test03_SimpleLDAPObjectWithFileno, self).reset_connection() From 4e53fc927945e294d74cfde1f0e66dee4327637d Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Wed, 31 Aug 2022 20:11:13 +0200 Subject: [PATCH 18/41] Add slapdtest.certs to setup.py packages to fix the deprecation warning --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b1939571..33cc2603 100644 --- a/setup.py +++ b/setup.py @@ -153,6 +153,7 @@ class OpenLDAP2: 'ldap.extop', 'ldap.schema', 'slapdtest', + 'slapdtest.certs', ], package_dir = {'': 'Lib',}, data_files = LDAP_CLASS.extra_files, From b3d6a8c2a6466dcf5f24cfa42d2bfc3815f9cedd Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Thu, 1 Sep 2022 11:32:03 -0700 Subject: [PATCH 19/41] Back out the removal of OPT_X_TLS and OPT_X_TLS_CTX options Closes #480 --- Doc/reference/ldap.rst | 10 ++++++++++ Lib/ldap/constants.py | 2 ++ Modules/constants_generated.h | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/Doc/reference/ldap.rst b/Doc/reference/ldap.rst index 2d5c4780..d059dfa4 100644 --- a/Doc/reference/ldap.rst +++ b/Doc/reference/ldap.rst @@ -409,6 +409,10 @@ TLS options get/set allowed cipher suites +.. py:data:: OPT_X_TLS_CTX + + get address of internal memory address of TLS context (**DO NOT USE**) + .. py:data:: OPT_X_TLS_PEERCERT Get peer's certificate as binary ASN.1 data structure (DER) @@ -472,6 +476,12 @@ TLS options get/set path to /dev/urandom (**DO NOT USE**) +.. py:data:: OPT_X_TLS + + .. deprecated:: 3.3.0 + The option is deprecated in OpenLDAP and should no longer be used. It + will be removed in the future. + .. note:: OpenLDAP supports several TLS/SSL libraries. OpenSSL is the most common diff --git a/Lib/ldap/constants.py b/Lib/ldap/constants.py index 1807fc55..0e7df6e7 100644 --- a/Lib/ldap/constants.py +++ b/Lib/ldap/constants.py @@ -267,6 +267,8 @@ class Str(Constant): Int('OPT_DEFBASE', optional=True), + TLSInt('OPT_X_TLS', optional=True), + TLSInt('OPT_X_TLS_CTX'), TLSInt('OPT_X_TLS_CACERTFILE'), TLSInt('OPT_X_TLS_CACERTDIR'), TLSInt('OPT_X_TLS_CERTFILE'), diff --git a/Modules/constants_generated.h b/Modules/constants_generated.h index 2d385549..3e59f828 100644 --- a/Modules/constants_generated.h +++ b/Modules/constants_generated.h @@ -202,6 +202,12 @@ add_int(OPT_DEFBASE); #if HAVE_TLS + +#if defined(LDAP_OPT_X_TLS) +add_int(OPT_X_TLS); +#endif + +add_int(OPT_X_TLS_CTX); add_int(OPT_X_TLS_CACERTFILE); add_int(OPT_X_TLS_CACERTDIR); add_int(OPT_X_TLS_CERTFILE); From 9dd59a9cefdf8980beca5d75ac5983fdde7f0d79 Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Thu, 15 Sep 2022 16:38:25 -0700 Subject: [PATCH 20/41] Prepare a new release --- CHANGES | 15 +++++++++++++++ Lib/ldap/pkginfo.py | 2 +- Lib/ldapurl.py | 2 +- Lib/ldif.py | 2 +- Lib/slapdtest/__init__.py | 2 +- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index b1ccc990..500fa1e7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,18 @@ +Released 3.4.3 2022-09-15 + +This is a minor release to bring back the removed OPT_X_TLS option. +Please note, it's still a deprecated option and it will be removed in 3.5.0. + +The following deprecated option has been brought back: +- ``OPT_X_TLS`` + +Fixes: +* Sphinx documentation is now successfully built +* pypy3 tests stability was improved +* setup.py deprecation warning is now resolved + + +---------------------------------------------------------------- Released 3.4.2 2022-07-06 This is a minor release to provide out-of-the-box compatibility with the merge diff --git a/Lib/ldap/pkginfo.py b/Lib/ldap/pkginfo.py index 4e195264..026e9101 100644 --- a/Lib/ldap/pkginfo.py +++ b/Lib/ldap/pkginfo.py @@ -1,6 +1,6 @@ """ meta attributes for packaging which does not import any dependencies """ -__version__ = '3.4.2' +__version__ = '3.4.3' __author__ = 'python-ldap project' __license__ = 'Python style' diff --git a/Lib/ldapurl.py b/Lib/ldapurl.py index e76528a7..964076d3 100644 --- a/Lib/ldapurl.py +++ b/Lib/ldapurl.py @@ -4,7 +4,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.2' +__version__ = '3.4.3' __all__ = [ # constants diff --git a/Lib/ldif.py b/Lib/ldif.py index 7561d09a..ae1d643d 100644 --- a/Lib/ldif.py +++ b/Lib/ldif.py @@ -3,7 +3,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.2' +__version__ = '3.4.3' __all__ = [ # constants diff --git a/Lib/slapdtest/__init__.py b/Lib/slapdtest/__init__.py index a49b13f7..7ab7d2bd 100644 --- a/Lib/slapdtest/__init__.py +++ b/Lib/slapdtest/__init__.py @@ -4,7 +4,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.2' +__version__ = '3.4.3' from slapdtest._slapdtest import SlapdObject, SlapdTestCase, SysLogHandler from slapdtest._slapdtest import requires_ldapi, requires_sasl, requires_tls From 88e74b923594693f9d6a7f666f1ce783f2f39762 Mon Sep 17 00:00:00 2001 From: Josh Thomas Date: Tue, 20 Dec 2022 20:58:16 -0600 Subject: [PATCH 21/41] Add Python 3.10 and 3.11 to CI and tox --- .github/workflows/ci.yml | 2 +- .github/workflows/tox-fedora.yml | 1 + setup.py | 2 ++ tox.ini | 4 +++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bc2ae0e..9700a8ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.6, 3.7, 3.8, 3.9, pypy3] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy3"] steps: - name: Checkout uses: "actions/checkout@v2" diff --git a/.github/workflows/tox-fedora.yml b/.github/workflows/tox-fedora.yml index c0dbb45c..cc75db90 100644 --- a/.github/workflows/tox-fedora.yml +++ b/.github/workflows/tox-fedora.yml @@ -23,6 +23,7 @@ jobs: - py38 - py39 - py310 + - py311 - c90-py36 - c90-py37 - py3-nosasltls diff --git a/setup.py b/setup.py index 33cc2603..2bba473e 100644 --- a/setup.py +++ b/setup.py @@ -90,6 +90,8 @@ class OpenLDAP2: 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', # Note: when updating Python versions, also change tox.ini and .github/workflows/* 'Topic :: Database', diff --git a/tox.ini b/tox.ini index aaef8b5a..3387d094 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ [tox] # Note: when updating Python versions, also change setup.py and .github/worlflows/* -envlist = py{36,37,38,39,310},c90-py{36,37},py3-nosasltls,doc,py3-trace,pypy3 +envlist = py{36,37,38,39,310,311},c90-py{36,37},py3-nosasltls,doc,py3-trace,pypy3 minver = 1.8 [gh-actions] @@ -14,6 +14,8 @@ python = 3.7: py37 3.8: py38, doc, py3-nosasltls 3.9: py39, py3-trace + 3.10: py310 + 3.11: py311 pypy3: pypy3 [testenv] From b8ad0c5ea7d2c4b295ea636c03124c9e5efb5eea Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Wed, 18 Jan 2023 19:17:00 -0800 Subject: [PATCH 22/41] Fix CI images after ubuntu-latest update Keep 20.04 for py3.6 testing. Replace the deprecated enchant package with enchant-2. --- .github/workflows/ci.yml | 4 ++-- .github/workflows/tox-fedora.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9700a8ed..2432e9e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: [push, pull_request] jobs: distros: name: "Ubuntu with Python ${{ matrix.python-version }}" - runs-on: "ubuntu-latest" + runs-on: "ubuntu-20.04" strategy: fail-fast: false matrix: @@ -18,7 +18,7 @@ jobs: run: | set -ex sudo apt update - sudo apt install -y ldap-utils slapd enchant libldap2-dev libsasl2-dev apparmor-utils + sudo apt install -y ldap-utils slapd enchant-2 libldap2-dev libsasl2-dev apparmor-utils - name: Disable AppArmor run: sudo aa-disable /usr/sbin/slapd - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/tox-fedora.yml b/.github/workflows/tox-fedora.yml index cc75db90..381a0b0c 100644 --- a/.github/workflows/tox-fedora.yml +++ b/.github/workflows/tox-fedora.yml @@ -32,4 +32,4 @@ jobs: - doc # Use GitHub's Linux Docker host - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 From ec74e5b0a60aa5716119aa06ac48e01344b5fdf2 Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Thu, 2 Feb 2023 21:34:08 -0800 Subject: [PATCH 23/41] Conscious Language: Rename master branch to main branch Additionally, rename sphinx configuration parameter master_doc to root_doc Fixes: https://github.com/python-ldap/python-ldap/issues/509 --- Doc/conf.py | 4 ++-- Doc/faq.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index b883736e..e79cfb34 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -50,8 +50,8 @@ # The suffix of source filenames. source_suffix = '.rst' -# The master toctree document. -master_doc = 'index' +# The root toctree document. +root_doc = 'index' # General substitutions. project = 'python-ldap' diff --git a/Doc/faq.rst b/Doc/faq.rst index e96fc030..39a6743c 100644 --- a/Doc/faq.rst +++ b/Doc/faq.rst @@ -13,7 +13,7 @@ Project **A3**: see file CHANGES in source distribution or `repository`_. -.. _repository: https://github.com/python-ldap/python-ldap/blob/master/CHANGES +.. _repository: https://github.com/python-ldap/python-ldap/blob/main/CHANGES Usage From 105925fe6db9cc6c71fafe16bddaa4abcbb8ddce Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Wed, 8 Feb 2023 02:21:53 +0100 Subject: [PATCH 24/41] fix(ReconnectLDAPObject): reconnect race condition Move calling `unbind_s()` inside the locked region so that `self._l` is handled atomically. Add a new parameter `force` to either forcefully close any previous connection or keep re-use the previous connection if it still is supposed to work. --- Lib/ldap/ldapobject.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index 9442e39b..7a9c17f6 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -893,7 +893,7 @@ def __setstate__(self,d): self._reconnect_lock = ldap.LDAPLock(desc='reconnect lock within %s' % (repr(self))) # XXX cannot pickle file, use default trace file self._trace_file = ldap._trace_file - self.reconnect(self._uri) + self.reconnect(self._uri,force=True) def _store_last_bind(self,_method,*args,**kwargs): self._last_bind = (_method,args,kwargs) @@ -914,11 +914,16 @@ def _restore_options(self): def passwd_s(self,*args,**kwargs): return self._apply_method_s(SimpleLDAPObject.passwd_s,*args,**kwargs) - def reconnect(self,uri,retry_max=1,retry_delay=60.0): + def reconnect(self,uri,retry_max=1,retry_delay=60.0,force=True): # Drop and clean up old connection completely # Reconnect self._reconnect_lock.acquire() try: + if hasattr(self,'_l'): + if force: + SimpleLDAPObject.unbind_s(self) + else: + return reconnect_counter = retry_max while reconnect_counter: counter_text = '%d. (of %d)' % (retry_max-reconnect_counter+1,retry_max) @@ -962,14 +967,12 @@ def reconnect(self,uri,retry_max=1,retry_delay=60.0): return # reconnect() def _apply_method_s(self,func,*args,**kwargs): - if not hasattr(self,'_l'): - self.reconnect(self._uri,retry_max=self._retry_max,retry_delay=self._retry_delay) + self.reconnect(self._uri,retry_max=self._retry_max,retry_delay=self._retry_delay,force=False) try: return func(self,*args,**kwargs) except ldap.SERVER_DOWN: - SimpleLDAPObject.unbind_s(self) # Try to reconnect - self.reconnect(self._uri,retry_max=self._retry_max,retry_delay=self._retry_delay) + self.reconnect(self._uri,retry_max=self._retry_max,retry_delay=self._retry_delay,force=True) # Re-try last operation return func(self,*args,**kwargs) From e756eac00a80240b9c708fba145ff664c134b957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lum=C3=ADr=20=27Frenzy=27=20Balhar?= Date: Fri, 14 Apr 2023 06:13:20 +0200 Subject: [PATCH 25/41] Switch tox-github-action from master to main branch --- .github/workflows/tox-fedora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tox-fedora.yml b/.github/workflows/tox-fedora.yml index 381a0b0c..4e88cee4 100644 --- a/.github/workflows/tox-fedora.yml +++ b/.github/workflows/tox-fedora.yml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Run Tox tests - uses: fedora-python/tox-github-action@master + uses: fedora-python/tox-github-action@main with: tox_env: ${{ matrix.tox_env }} dnf_install: > From 91e0918f822e5a28d5b66b0bdf9b99b596f5be3c Mon Sep 17 00:00:00 2001 From: Diogo Teles Sant'Anna Date: Fri, 2 Jun 2023 12:46:09 -0300 Subject: [PATCH 26/41] ci: set minimal permissions on workflows (#525) Signed-off-by: Diogo Teles Sant'Anna --- .github/workflows/ci.yml | 3 +++ .github/workflows/tox-fedora.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2432e9e8..86e8ba51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,9 @@ name: CI on: [push, pull_request] +permissions: + contents: read + jobs: distros: name: "Ubuntu with Python ${{ matrix.python-version }}" diff --git a/.github/workflows/tox-fedora.yml b/.github/workflows/tox-fedora.yml index 4e88cee4..f41024a0 100644 --- a/.github/workflows/tox-fedora.yml +++ b/.github/workflows/tox-fedora.yml @@ -2,6 +2,9 @@ on: [push, pull_request] name: Tox on Fedora +permissions: + contents: read + jobs: tox_test: name: Tox env "${{matrix.tox_env}}" on Fedora From 72c1b5e0f37f74b1a68e67b6b5712d395d577bb9 Mon Sep 17 00:00:00 2001 From: Diogo Teles Sant'Anna Date: Thu, 27 Jul 2023 20:55:14 -0300 Subject: [PATCH 27/41] docs: create Security Policy (#530) --- SECURITY.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..752b1394 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the latest release. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at our [security advisory](https://github.com/python-ldap/python-ldap/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base. From 30fe146e6c8e881a2db2a3f6b60fb6201bf6a534 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Tue, 22 Aug 2023 20:02:46 -0400 Subject: [PATCH 28/41] Update article links in resources.rst (#533) Fix broken links. --- Doc/resources.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/resources.rst b/Doc/resources.rst index 56cb1a1a..795f8b63 100644 --- a/Doc/resources.rst +++ b/Doc/resources.rst @@ -8,13 +8,13 @@ members. Therefore some information might be outdated or links might be broken. *Python LDAP Applications* articles by Matt Butcher --------------------------------------------------- -* `Part 1 - Installing and Configuring the Python-LDAP Library and Binding to an LDAP Directory `_ +* `Part 1 - Installing and Configuring the Python-LDAP Library and Binding to an LDAP Directory `_ This also covers SASL. -* `Part 2 - LDAP Operations `_ -* `Part 3 - More LDAP Operations and the LDAP URL Library `_ -* `Part 4 - LDAP Schema `_ +* `Part 2 - LDAP Operations `_ +* `Part 3 - More LDAP Operations and the LDAP URL Library `_ +* `Part 4 - LDAP Schema `_ Gee, someone waded through the badly documented mysteries of module :mod:`ldap.schema`. From 2229d83646895ce041a5582400fa77e82d40c2c7 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 4 Oct 2023 18:42:53 +0200 Subject: [PATCH 29/41] Test with Python 3.12 (#537) --- .github/workflows/ci.yml | 29 ++++++++++++++++++++++++----- .github/workflows/tox-fedora.yml | 1 + Modules/options.c | 4 ++-- setup.py | 1 + tox.ini | 10 ++++++++-- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86e8ba51..37843f31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,13 @@ --- name: CI -on: [push, pull_request] +on: + push: + pull_request: + schedule: + # every Monday + - cron: '30 4 * * 1' + workflow_dispatch: permissions: contents: read @@ -9,14 +15,26 @@ permissions: jobs: distros: name: "Ubuntu with Python ${{ matrix.python-version }}" - runs-on: "ubuntu-20.04" + runs-on: "${{ matrix.image }}" strategy: fail-fast: false matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy3"] + python-version: + - "3.7" + - "3.8" + - "3.9" + - "3.10" + - "3.11" + - "3.12" + - "pypy3.9" + image: + - "ubuntu-22.04" + include: + - python-version: "3.6" + image: "ubuntu-20.04" steps: - name: Checkout - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" - name: Install apt dependencies run: | set -ex @@ -25,9 +43,10 @@ jobs: - name: Disable AppArmor run: sudo aa-disable /usr/sbin/slapd - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + allow-prereleases: true - name: "Install Python dependencies" run: | set -xe diff --git a/.github/workflows/tox-fedora.yml b/.github/workflows/tox-fedora.yml index f41024a0..b86303fe 100644 --- a/.github/workflows/tox-fedora.yml +++ b/.github/workflows/tox-fedora.yml @@ -27,6 +27,7 @@ jobs: - py39 - py310 - py311 + - py312 - c90-py36 - c90-py37 - py3-nosasltls diff --git a/Modules/options.c b/Modules/options.c index 1a22bed1..a621f81a 100644 --- a/Modules/options.c +++ b/Modules/options.c @@ -207,8 +207,8 @@ LDAP_set_option(LDAPObject *self, int option, PyObject *value) } else { PyErr_Format(PyExc_ValueError, - "timeout must be >= 0 or -1/None for infinity, got %f", - doubleval); + "timeout must be >= 0 or -1/None for infinity, got %S", + value); return 0; } break; diff --git a/setup.py b/setup.py index 2bba473e..6da3f491 100644 --- a/setup.py +++ b/setup.py @@ -92,6 +92,7 @@ class OpenLDAP2: 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', # Note: when updating Python versions, also change tox.ini and .github/workflows/* 'Topic :: Database', diff --git a/tox.ini b/tox.ini index 3387d094..beade024 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ [tox] # Note: when updating Python versions, also change setup.py and .github/worlflows/* -envlist = py{36,37,38,39,310,311},c90-py{36,37},py3-nosasltls,doc,py3-trace,pypy3 +envlist = py{36,37,38,39,310,311,312},c90-py{36,37},py3-nosasltls,doc,py3-trace,pypy3.9 minver = 1.8 [gh-actions] @@ -16,7 +16,8 @@ python = 3.9: py39, py3-trace 3.10: py310 3.11: py311 - pypy3: pypy3 + 3.12: py312 + pypy3.9: pypy3.9 [testenv] deps = @@ -28,6 +29,11 @@ setenv = commands = {envpython} -bb -Werror \ -m unittest discover -v -s Tests -p 't_*' {posargs} +[testenv:py312] +# Python 3.12 headers are incompatible with declaration-after-statement +setenv = + CFLAGS=-Wno-int-in-bool-context -Werror -std=c99 + [testenv:py3-nosasltls] basepython = python3 # don't install, install dependencies manually From 1490e999e10960f0fdf974f6da804a2fc55e4b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 1 Nov 2023 17:46:35 +0000 Subject: [PATCH 30/41] Claim ownership of socket once we've passed it to libldap Fixes: https://github.com/python-ldap/python-ldap/issues/460 Closes: https://github.com/python-ldap/python-ldap/pull/543 --- Tests/t_ldapobject.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/Tests/t_ldapobject.py b/Tests/t_ldapobject.py index ccc7d218..ada5f990 100644 --- a/Tests/t_ldapobject.py +++ b/Tests/t_ldapobject.py @@ -647,24 +647,14 @@ def test105_reconnect_restore(self): @requires_init_fd() class Test03_SimpleLDAPObjectWithFileno(Test00_SimpleLDAPObject): def _open_ldap_conn(self, who=None, cred=None, **kwargs): - if hasattr(self, '_sock'): - raise RuntimeError("socket already connected") - self._sock = socket.create_connection( + sock = socket.create_connection( (self.server.hostname, self.server.port) ) - return super()._open_ldap_conn( - who=who, cred=cred, fileno=self._sock.fileno(), **kwargs + result = super()._open_ldap_conn( + who=who, cred=cred, fileno=sock.fileno(), **kwargs ) - - def tearDown(self): - self._sock.close() - delattr(self, '_sock') - super().tearDown() - - def reset_connection(self): - self._sock.close() - delattr(self, '_sock') - super(Test03_SimpleLDAPObjectWithFileno, self).reset_connection() + sock.detach() + return result if __name__ == '__main__': From 75a765f82fed2e3f418a1152b3af02f7d1e2629e Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 30 Oct 2023 09:19:41 +0100 Subject: [PATCH 31/41] refactor: Merge all header files Merge all header files except `constants_generated.h` into a single header file `pythonldap.h`. A single header file makes it far easier to port python-ldap to heap types and module state for Per-Interpreter GIL. `pythonldap.h` uses new macros `PYLDAP_FUNC` and `PYLDAP_DATA` to declare functions and data, which are used across C files. Remove unused macro `streq`. See: https://github.com/python-ldap/python-ldap/issues/540 Signed-off-by: Christian Heimes --- Makefile | 3 +- Modules/LDAPObject.c | 8 +-- Modules/LDAPObject.h | 38 ------------ Modules/berval.c | 3 +- Modules/berval.h | 11 ---- Modules/common.c | 2 +- Modules/common.h | 68 --------------------- Modules/constants.c | 4 +- Modules/constants.h | 24 -------- Modules/functions.c | 7 +-- Modules/functions.h | 9 --- Modules/ldapcontrol.c | 6 +- Modules/ldapcontrol.h | 13 ---- Modules/ldapmodule.c | 7 +-- Modules/message.c | 6 +- Modules/message.h | 11 ---- Modules/options.c | 7 +-- Modules/options.h | 7 --- Modules/pythonldap.h | 137 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 9 +-- 20 files changed, 149 insertions(+), 231 deletions(-) delete mode 100644 Modules/LDAPObject.h delete mode 100644 Modules/berval.h delete mode 100644 Modules/common.h delete mode 100644 Modules/constants.h delete mode 100644 Modules/functions.h delete mode 100644 Modules/ldapcontrol.h delete mode 100644 Modules/message.h delete mode 100644 Modules/options.h create mode 100644 Modules/pythonldap.h diff --git a/Makefile b/Makefile index 577ba883..2b52ddf5 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,8 @@ valgrind: build $(PYTHON_SUPP) autoformat: indent black indent: - indent Modules/*.c Modules/*.h + indent Modules/*.c + indent -npsl Modules/pythonldap.h rm -f Modules/*.c~ Modules/*.h~ black: diff --git a/Modules/LDAPObject.c b/Modules/LDAPObject.c index da18d575..eaf831bd 100644 --- a/Modules/LDAPObject.c +++ b/Modules/LDAPObject.c @@ -1,16 +1,10 @@ /* See https://www.python-ldap.org/ for details. */ -#include "common.h" +#include "pythonldap.h" #include "patchlevel.h" #include #include -#include "constants.h" -#include "LDAPObject.h" -#include "ldapcontrol.h" -#include "message.h" -#include "berval.h" -#include "options.h" #ifdef HAVE_SASL #include diff --git a/Modules/LDAPObject.h b/Modules/LDAPObject.h deleted file mode 100644 index 4af0b382..00000000 --- a/Modules/LDAPObject.h +++ /dev/null @@ -1,38 +0,0 @@ -/* See https://www.python-ldap.org/ for details. */ - -#ifndef __h_LDAPObject -#define __h_LDAPObject - -#include "common.h" - -typedef struct { - PyObject_HEAD LDAP *ldap; - PyThreadState *_save; /* for thread saving on referrals */ - int valid; -} LDAPObject; - -extern PyTypeObject LDAP_Type; - -#define LDAPObject_Check(v) (Py_TYPE(v) == &LDAP_Type) - -extern LDAPObject *newLDAPObject(LDAP *); - -/* macros to allow thread saving in the context of an LDAP connection */ - -#define LDAP_BEGIN_ALLOW_THREADS( l ) \ - { \ - LDAPObject *lo = (l); \ - if (lo->_save != NULL) \ - Py_FatalError( "saving thread twice?" ); \ - lo->_save = PyEval_SaveThread(); \ - } - -#define LDAP_END_ALLOW_THREADS( l ) \ - { \ - LDAPObject *lo = (l); \ - PyThreadState *_save = lo->_save; \ - lo->_save = NULL; \ - PyEval_RestoreThread( _save ); \ - } - -#endif /* __h_LDAPObject */ diff --git a/Modules/berval.c b/Modules/berval.c index 6917baef..39cc98a8 100644 --- a/Modules/berval.c +++ b/Modules/berval.c @@ -1,7 +1,6 @@ /* See https://www.python-ldap.org/ for details. */ -#include "common.h" -#include "berval.h" +#include "pythonldap.h" /* * Copies out the data from a berval, and returns it as a new Python object, diff --git a/Modules/berval.h b/Modules/berval.h deleted file mode 100644 index 9c427240..00000000 --- a/Modules/berval.h +++ /dev/null @@ -1,11 +0,0 @@ -/* See https://www.python-ldap.org/ for details. */ - -#ifndef __h_berval -#define __h_berval - -#include "common.h" - -PyObject *LDAPberval_to_object(const struct berval *bv); -PyObject *LDAPberval_to_unicode_object(const struct berval *bv); - -#endif /* __h_berval_ */ diff --git a/Modules/common.c b/Modules/common.c index 9d7001c0..4cfee744 100644 --- a/Modules/common.c +++ b/Modules/common.c @@ -1,7 +1,7 @@ /* Miscellaneous common routines * See https://www.python-ldap.org/ for details. */ -#include "common.h" +#include "pythonldap.h" /* dynamically add the methods into the module dictionary d */ diff --git a/Modules/common.h b/Modules/common.h deleted file mode 100644 index bc554c85..00000000 --- a/Modules/common.h +++ /dev/null @@ -1,68 +0,0 @@ -/* common utility macros - * See https://www.python-ldap.org/ for details. */ - -#ifndef __h_common -#define __h_common - -#define PY_SSIZE_T_CLEAN - -#include "Python.h" - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include - -#if LDAP_VENDOR_VERSION < 20400 -#error Current python-ldap requires OpenLDAP 2.4.x -#endif - -#if LDAP_VENDOR_VERSION >= 20448 - /* openldap.h with ldap_init_fd() was introduced in 2.4.48 - * see https://bugs.openldap.org/show_bug.cgi?id=8671 - */ -#define HAVE_LDAP_INIT_FD 1 -#include -#elif (defined(__APPLE__) && (LDAP_VENDOR_VERSION == 20428)) -/* macOS system libldap 2.4.28 does not have ldap_init_fd symbol */ -#undef HAVE_LDAP_INIT_FD -#else - /* ldap_init_fd() has been around for a very long time - * SSSD has been defining the function for a while, so it's probably OK. - */ -#define HAVE_LDAP_INIT_FD 1 -#define LDAP_PROTO_TCP 1 -#define LDAP_PROTO_UDP 2 -#define LDAP_PROTO_IPC 3 -extern int ldap_init_fd(ber_socket_t fd, int proto, LDAP_CONST char *url, - LDAP **ldp); -#endif - -#if defined(MS_WINDOWS) -#include -#else /* unix */ -#include -#include -#include -#endif - -#include -#define streq( a, b ) \ - ( (*(a)==*(b)) && 0==strcmp(a,b) ) - -extern PyObject *LDAPerror_TypeError(const char *, PyObject *); - -void LDAPadd_methods(PyObject *d, PyMethodDef *methods); - -#define PyNone_Check(o) ((o) == Py_None) - -/* Py2/3 compatibility */ -#if PY_VERSION_HEX >= 0x03000000 -/* In Python 3, alias PyInt to PyLong */ -#define PyInt_FromLong PyLong_FromLong -#endif - -#endif /* __h_common_ */ diff --git a/Modules/constants.c b/Modules/constants.c index 8d6f63b0..b70db245 100644 --- a/Modules/constants.c +++ b/Modules/constants.c @@ -1,9 +1,7 @@ /* constants defined for LDAP * See https://www.python-ldap.org/ for details. */ -#include "common.h" -#include "constants.h" -#include "ldapcontrol.h" +#include "pythonldap.h" /* the base exception class */ diff --git a/Modules/constants.h b/Modules/constants.h deleted file mode 100644 index 7b9ce53e..00000000 --- a/Modules/constants.h +++ /dev/null @@ -1,24 +0,0 @@ -/* See https://www.python-ldap.org/ for details. */ - -#ifndef __h_constants_ -#define __h_constants_ - -#include "common.h" - -extern int LDAPinit_constants(PyObject *m); -extern PyObject *LDAPconstant(int); - -extern PyObject *LDAPexception_class; -extern PyObject *LDAPerror(LDAP *); -extern PyObject *LDAPraise_for_message(LDAP *, LDAPMessage *m); -PyObject *LDAPerr(int errnum); - -#ifndef LDAP_CONTROL_PAGE_OID -#define LDAP_CONTROL_PAGE_OID "1.2.840.113556.1.4.319" -#endif /* !LDAP_CONTROL_PAGE_OID */ - -#ifndef LDAP_CONTROL_VALUESRETURNFILTER -#define LDAP_CONTROL_VALUESRETURNFILTER "1.2.826.0.1.3344810.2.3" /* RFC 3876 */ -#endif /* !LDAP_CONTROL_VALUESRETURNFILTER */ - -#endif /* __h_constants_ */ diff --git a/Modules/functions.c b/Modules/functions.c index b811708f..f7d9cf37 100644 --- a/Modules/functions.c +++ b/Modules/functions.c @@ -1,11 +1,6 @@ /* See https://www.python-ldap.org/ for details. */ -#include "common.h" -#include "functions.h" -#include "LDAPObject.h" -#include "berval.h" -#include "constants.h" -#include "options.h" +#include "pythonldap.h" /* ldap_initialize */ diff --git a/Modules/functions.h b/Modules/functions.h deleted file mode 100644 index 2aef9740..00000000 --- a/Modules/functions.h +++ /dev/null @@ -1,9 +0,0 @@ -/* See https://www.python-ldap.org/ for details. */ - -#ifndef __h_functions_ -#define __h_functions_ - -#include "common.h" -extern void LDAPinit_functions(PyObject *); - -#endif /* __h_functions_ */ diff --git a/Modules/ldapcontrol.c b/Modules/ldapcontrol.c index e287e9a3..4a37b614 100644 --- a/Modules/ldapcontrol.c +++ b/Modules/ldapcontrol.c @@ -1,10 +1,6 @@ /* See https://www.python-ldap.org/ for details. */ -#include "common.h" -#include "LDAPObject.h" -#include "ldapcontrol.h" -#include "berval.h" -#include "constants.h" +#include "pythonldap.h" /* Prints to stdout the contents of an array of LDAPControl objects */ diff --git a/Modules/ldapcontrol.h b/Modules/ldapcontrol.h deleted file mode 100644 index 74cae423..00000000 --- a/Modules/ldapcontrol.h +++ /dev/null @@ -1,13 +0,0 @@ -/* See https://www.python-ldap.org/ for details. */ - -#ifndef __h_ldapcontrol -#define __h_ldapcontrol - -#include "common.h" - -void LDAPinit_control(PyObject *d); -void LDAPControl_List_DEL(LDAPControl **); -int LDAPControls_from_object(PyObject *, LDAPControl ***); -PyObject *LDAPControls_to_List(LDAPControl **ldcs); - -#endif /* __h_ldapcontrol */ diff --git a/Modules/ldapmodule.c b/Modules/ldapmodule.c index 34d5a24c..8562337b 100644 --- a/Modules/ldapmodule.c +++ b/Modules/ldapmodule.c @@ -1,11 +1,6 @@ /* See https://www.python-ldap.org/ for details. */ -#include "common.h" -#include "constants.h" -#include "functions.h" -#include "ldapcontrol.h" - -#include "LDAPObject.h" +#include "pythonldap.h" #if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit__ldap(void); diff --git a/Modules/message.c b/Modules/message.c index 22aa313c..f1403237 100644 --- a/Modules/message.c +++ b/Modules/message.c @@ -1,10 +1,6 @@ /* See https://www.python-ldap.org/ for details. */ -#include "common.h" -#include "message.h" -#include "berval.h" -#include "ldapcontrol.h" -#include "constants.h" +#include "pythonldap.h" /* * Converts an LDAP message into a Python structure. diff --git a/Modules/message.h b/Modules/message.h deleted file mode 100644 index ed73f32c..00000000 --- a/Modules/message.h +++ /dev/null @@ -1,11 +0,0 @@ -/* See https://www.python-ldap.org/ for details. */ - -#ifndef __h_message -#define __h_message - -#include "common.h" - -extern PyObject *LDAPmessage_to_python(LDAP *ld, LDAPMessage *m, int add_ctrls, - int add_intermediates); - -#endif /* __h_message_ */ diff --git a/Modules/options.c b/Modules/options.c index a621f81a..df55ed05 100644 --- a/Modules/options.c +++ b/Modules/options.c @@ -1,11 +1,6 @@ /* See https://www.python-ldap.org/ for details. */ -#include "common.h" -#include "constants.h" -#include "LDAPObject.h" -#include "ldapcontrol.h" -#include "options.h" -#include "berval.h" +#include "pythonldap.h" void set_timeval_from_double(struct timeval *tv, double d) diff --git a/Modules/options.h b/Modules/options.h deleted file mode 100644 index fd6a5ce2..00000000 --- a/Modules/options.h +++ /dev/null @@ -1,7 +0,0 @@ -/* See https://www.python-ldap.org/ for details. */ - -int LDAP_optionval_by_name(const char *name); -int LDAP_set_option(LDAPObject *self, int option, PyObject *value); -PyObject *LDAP_get_option(LDAPObject *self, int option); - -void set_timeval_from_double(struct timeval *tv, double d); diff --git a/Modules/pythonldap.h b/Modules/pythonldap.h new file mode 100644 index 00000000..ae6a1269 --- /dev/null +++ b/Modules/pythonldap.h @@ -0,0 +1,137 @@ +/* common utility macros + * See https://www.python-ldap.org/ for details. */ + +#ifndef pythonldap_h +#define pythonldap_h + +/* *** common *** */ +#define PY_SSIZE_T_CLEAN + +#include "Python.h" + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include + +/* Py2/3 compatibility */ +#if PY_VERSION_HEX >= 0x03000000 +/* In Python 3, alias PyInt to PyLong */ +#define PyInt_FromLong PyLong_FromLong +#endif + +#if LDAP_VENDOR_VERSION < 20400 +#error Current python-ldap requires OpenLDAP 2.4.x +#endif + +#if LDAP_VENDOR_VERSION >= 20448 + /* openldap.h with ldap_init_fd() was introduced in 2.4.48 + * see https://bugs.openldap.org/show_bug.cgi?id=8671 + */ +#define HAVE_LDAP_INIT_FD 1 +#include +#elif (defined(__APPLE__) && (LDAP_VENDOR_VERSION == 20428)) +/* macOS system libldap 2.4.28 does not have ldap_init_fd symbol */ +#undef HAVE_LDAP_INIT_FD +#else + /* ldap_init_fd() has been around for a very long time + * SSSD has been defining the function for a while, so it's probably OK. + */ +#define HAVE_LDAP_INIT_FD 1 +#define LDAP_PROTO_TCP 1 +#define LDAP_PROTO_UDP 2 +#define LDAP_PROTO_IPC 3 +LDAP_F(int) ldap_init_fd(ber_socket_t fd, int proto, LDAP_CONST char *url, + LDAP **ldp); +#endif + +#if defined(MS_WINDOWS) +#include +#else /* unix */ +#include +#include +#include +#endif + +#define PYLDAP_FUNC(rtype) rtype +#define PYLDAP_DATA(rtype) extern rtype + +PYLDAP_FUNC(PyObject *) LDAPerror_TypeError(const char *, PyObject *); + +PYLDAP_FUNC(void) LDAPadd_methods(PyObject *d, PyMethodDef *methods); + +#define PyNone_Check(o) ((o) == Py_None) + +/* *** berval *** */ +PYLDAP_FUNC(PyObject *) LDAPberval_to_object(const struct berval *bv); +PYLDAP_FUNC(PyObject *) LDAPberval_to_unicode_object(const struct berval *bv); + +/* *** constants *** */ +PYLDAP_FUNC(int) LDAPinit_constants(PyObject *m); + +PYLDAP_DATA(PyObject *) LDAPexception_class; +PYLDAP_FUNC(PyObject *) LDAPerror(LDAP *); +PYLDAP_FUNC(PyObject *) LDAPraise_for_message(LDAP *, LDAPMessage *m); +PYLDAP_FUNC(PyObject *) LDAPerr(int errnum); + +#ifndef LDAP_CONTROL_PAGE_OID +#define LDAP_CONTROL_PAGE_OID "1.2.840.113556.1.4.319" +#endif /* !LDAP_CONTROL_PAGE_OID */ + +#ifndef LDAP_CONTROL_VALUESRETURNFILTER +#define LDAP_CONTROL_VALUESRETURNFILTER "1.2.826.0.1.3344810.2.3" /* RFC 3876 */ +#endif /* !LDAP_CONTROL_VALUESRETURNFILTER */ + +/* *** functions *** */ +PYLDAP_FUNC(void) LDAPinit_functions(PyObject *); + +/* *** ldapcontrol *** */ +PYLDAP_FUNC(void) LDAPinit_control(PyObject *d); +PYLDAP_FUNC(void) LDAPControl_List_DEL(LDAPControl **); +PYLDAP_FUNC(int) LDAPControls_from_object(PyObject *, LDAPControl ***); +PYLDAP_FUNC(PyObject *) LDAPControls_to_List(LDAPControl **ldcs); + +/* *** ldapobject *** */ +typedef struct { + PyObject_HEAD LDAP *ldap; + PyThreadState *_save; /* for thread saving on referrals */ + int valid; +} LDAPObject; + +PYLDAP_DATA(PyTypeObject) LDAP_Type; +PYLDAP_FUNC(LDAPObject *) newLDAPObject(LDAP *); + +/* macros to allow thread saving in the context of an LDAP connection */ + +#define LDAP_BEGIN_ALLOW_THREADS( l ) \ + { \ + LDAPObject *lo = (l); \ + if (lo->_save != NULL) \ + Py_FatalError( "saving thread twice?" ); \ + lo->_save = PyEval_SaveThread(); \ + } + +#define LDAP_END_ALLOW_THREADS( l ) \ + { \ + LDAPObject *lo = (l); \ + PyThreadState *_save = lo->_save; \ + lo->_save = NULL; \ + PyEval_RestoreThread( _save ); \ + } + +/* *** messages *** */ +PYLDAP_FUNC(PyObject *) +LDAPmessage_to_python(LDAP *ld, LDAPMessage *m, int add_ctrls, + int add_intermediates); + +/* *** options *** */ +PYLDAP_FUNC(int) LDAP_optionval_by_name(const char *name); +PYLDAP_FUNC(int) LDAP_set_option(LDAPObject *self, int option, + PyObject *value); +PYLDAP_FUNC(PyObject *) LDAP_get_option(LDAPObject *self, int option); +PYLDAP_FUNC(void) set_timeval_from_double(struct timeval *tv, double d); + +#endif /* pythonldap_h */ diff --git a/setup.py b/setup.py index 6da3f491..dbf66a04 100644 --- a/setup.py +++ b/setup.py @@ -117,15 +117,8 @@ class OpenLDAP2: 'Modules/berval.c', ], depends = [ - 'Modules/LDAPObject.h', - 'Modules/berval.h', - 'Modules/common.h', + 'Modules/pythonldap.h', 'Modules/constants_generated.h', - 'Modules/constants.h', - 'Modules/functions.h', - 'Modules/ldapcontrol.h', - 'Modules/message.h', - 'Modules/options.h', ], libraries = LDAP_CLASS.libs, include_dirs = ['Modules'] + LDAP_CLASS.include_dirs, From f48101097eb08f902daed5b8e7836c54cf44b0f4 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 30 Oct 2023 09:40:12 +0100 Subject: [PATCH 32/41] refactor: Remove Python 2 vestiges The C code had a few version checks for Python 2. python-ldap requires Python >= 3.6. Signed-off-by: Christian Heimes --- Modules/LDAPObject.c | 51 +++++++++++--------------------------------- Modules/constants.c | 8 +++---- Modules/ldapmodule.c | 45 ++++++++++---------------------------- Modules/options.c | 2 +- Modules/pythonldap.h | 6 ------ 5 files changed, 28 insertions(+), 84 deletions(-) diff --git a/Modules/LDAPObject.c b/Modules/LDAPObject.c index eaf831bd..71fac73e 100644 --- a/Modules/LDAPObject.c +++ b/Modules/LDAPObject.c @@ -270,13 +270,8 @@ attrs_from_List(PyObject *attrlist, char ***attrsp) if (attrlist == Py_None) { /* None means a NULL attrlist */ -#if PY_MAJOR_VERSION == 2 - } - else if (PyBytes_Check(attrlist)) { -#else } else if (PyUnicode_Check(attrlist)) { -#endif /* caught by John Benninghoff */ LDAPerror_TypeError ("attrs_from_List(): expected *list* of strings, not a string", @@ -287,11 +282,7 @@ attrs_from_List(PyObject *attrlist, char ***attrsp) PyObject *item = NULL; Py_ssize_t i, len, strlen; -#if PY_MAJOR_VERSION >= 3 const char *str; -#else - char *str; -#endif seq = PySequence_Fast(attrlist, "expected list of strings or None"); if (seq == NULL) @@ -309,24 +300,12 @@ attrs_from_List(PyObject *attrlist, char ***attrsp) item = PySequence_Fast_GET_ITEM(seq, i); if (item == NULL) goto error; -#if PY_MAJOR_VERSION == 2 - /* Encoded in Python to UTF-8 */ - if (!PyBytes_Check(item)) { - LDAPerror_TypeError - ("attrs_from_List(): expected bytes in list", item); - goto error; - } - if (PyBytes_AsStringAndSize(item, &str, &strlen) == -1) { - goto error; - } -#else if (!PyUnicode_Check(item)) { LDAPerror_TypeError ("attrs_from_List(): expected string in list", item); goto error; } str = PyUnicode_AsUTF8AndSize(item, &strlen); -#endif /* Make a copy. PyBytes_AsString* / PyUnicode_AsUTF8* return * internal values that must be treated like const char. Python * 3.7 actually returns a const char. @@ -515,7 +494,7 @@ l_ldap_add_ext(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* ldap_simple_bind */ @@ -566,7 +545,7 @@ l_ldap_simple_bind(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } #ifdef HAVE_SASL @@ -724,7 +703,7 @@ l_ldap_sasl_bind_s(LDAPObject *self, PyObject *args) } else if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(ldaperror); + return PyLong_FromLong(ldaperror); } static PyObject * @@ -751,15 +730,9 @@ l_ldap_sasl_interactive_bind_s(LDAPObject *self, PyObject *args) * unsigned int, we need to use the "I" flag if we're running Python 2.3+ and a * "i" otherwise. */ -#if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 3) - if (!PyArg_ParseTuple - (args, "sOOOi:sasl_interactive_bind_s", &who, &SASLObject, - &serverctrls, &clientctrls, &sasl_flags)) -#else if (!PyArg_ParseTuple (args, "sOOOI:sasl_interactive_bind_s", &who, &SASLObject, &serverctrls, &clientctrls, &sasl_flags)) -#endif return NULL; if (not_valid(self)) @@ -803,7 +776,7 @@ l_ldap_sasl_interactive_bind_s(LDAPObject *self, PyObject *args) if (msgid != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } #endif @@ -852,7 +825,7 @@ l_ldap_cancel(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } #endif @@ -906,7 +879,7 @@ l_ldap_compare_ext(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* ldap_delete_ext */ @@ -952,7 +925,7 @@ l_ldap_delete_ext(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* ldap_modify_ext */ @@ -1009,7 +982,7 @@ l_ldap_modify_ext(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* ldap_rename */ @@ -1059,7 +1032,7 @@ l_ldap_rename(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* ldap_result4 */ @@ -1275,7 +1248,7 @@ l_ldap_search_ext(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* ldap_whoami_s (available since OpenLDAP 2.1.13) */ @@ -1445,7 +1418,7 @@ l_ldap_passwd(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* ldap_extended_operation */ @@ -1496,7 +1469,7 @@ l_ldap_extended_operation(LDAPObject *self, PyObject *args) if (ldaperror != LDAP_SUCCESS) return LDAPerror(self->ldap); - return PyInt_FromLong(msgid); + return PyLong_FromLong(msgid); } /* methods */ diff --git a/Modules/constants.c b/Modules/constants.c index b70db245..f0a0da94 100644 --- a/Modules/constants.c +++ b/Modules/constants.c @@ -105,20 +105,20 @@ LDAPraise_for_message(LDAP *l, LDAPMessage *m) } if (msgtype > 0) { - pyresult = PyInt_FromLong(msgtype); + pyresult = PyLong_FromLong(msgtype); if (pyresult) PyDict_SetItemString(info, "msgtype", pyresult); Py_XDECREF(pyresult); } if (msgid >= 0) { - pyresult = PyInt_FromLong(msgid); + pyresult = PyLong_FromLong(msgid); if (pyresult) PyDict_SetItemString(info, "msgid", pyresult); Py_XDECREF(pyresult); } - pyresult = PyInt_FromLong(errnum); + pyresult = PyLong_FromLong(errnum); if (pyresult) PyDict_SetItemString(info, "result", pyresult); Py_XDECREF(pyresult); @@ -129,7 +129,7 @@ LDAPraise_for_message(LDAP *l, LDAPMessage *m) Py_XDECREF(str); if (myerrno != 0) { - pyerrno = PyInt_FromLong(myerrno); + pyerrno = PyLong_FromLong(myerrno); if (pyerrno) PyDict_SetItemString(info, "errno", pyerrno); Py_XDECREF(pyerrno); diff --git a/Modules/ldapmodule.c b/Modules/ldapmodule.c index 8562337b..cb3f58fb 100644 --- a/Modules/ldapmodule.c +++ b/Modules/ldapmodule.c @@ -2,12 +2,6 @@ #include "pythonldap.h" -#if PY_MAJOR_VERSION >= 3 -PyMODINIT_FUNC PyInit__ldap(void); -#else -PyMODINIT_FUNC init_ldap(void); -#endif - #define _STR(x) #x #define STR(x) _STR(x) @@ -28,27 +22,24 @@ static PyMethodDef methods[] = { {NULL, NULL} }; +static struct PyModuleDef ldap_moduledef = { + PyModuleDef_HEAD_INIT, + "_ldap", /* m_name */ + "", /* m_doc */ + -1, /* m_size */ + methods, /* m_methods */ +}; + /* module initialisation */ -/* Common initialization code */ -PyObject * -init_ldap_module(void) +PyMODINIT_FUNC +PyInit__ldap() { PyObject *m, *d; /* Create the module and add the functions */ -#if PY_MAJOR_VERSION >= 3 - static struct PyModuleDef ldap_moduledef = { - PyModuleDef_HEAD_INIT, - "_ldap", /* m_name */ - "", /* m_doc */ - -1, /* m_size */ - methods, /* m_methods */ - }; m = PyModule_Create(&ldap_moduledef); -#else - m = Py_InitModule("_ldap", methods); -#endif + /* Initialize LDAP class */ if (PyType_Ready(&LDAP_Type) < 0) { Py_DECREF(m); @@ -73,17 +64,3 @@ init_ldap_module(void) return m; } - -#if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC -init_ldap() -{ - init_ldap_module(); -} -#else -PyMODINIT_FUNC -PyInit__ldap() -{ - return init_ldap_module(); -} -#endif diff --git a/Modules/options.c b/Modules/options.c index df55ed05..4577b075 100644 --- a/Modules/options.c +++ b/Modules/options.c @@ -368,7 +368,7 @@ LDAP_get_option(LDAPObject *self, int option) res = LDAP_int_get_option(self, option, &intval); if (res != LDAP_OPT_SUCCESS) return option_error(res, "ldap_get_option"); - return PyInt_FromLong(intval); + return PyLong_FromLong(intval); #ifdef LDAP_OPT_TCP_USER_TIMEOUT case LDAP_OPT_TCP_USER_TIMEOUT: diff --git a/Modules/pythonldap.h b/Modules/pythonldap.h index ae6a1269..7703af5e 100644 --- a/Modules/pythonldap.h +++ b/Modules/pythonldap.h @@ -17,12 +17,6 @@ #include #include -/* Py2/3 compatibility */ -#if PY_VERSION_HEX >= 0x03000000 -/* In Python 3, alias PyInt to PyLong */ -#define PyInt_FromLong PyLong_FromLong -#endif - #if LDAP_VENDOR_VERSION < 20400 #error Current python-ldap requires OpenLDAP 2.4.x #endif From 16a3a3c0175aa51ee22efda118dbaeb3881cec3c Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Fri, 17 Nov 2023 12:29:34 -0800 Subject: [PATCH 33/41] Prepare a new release --- CHANGES | 17 +++++++++++++++++ Lib/ldap/pkginfo.py | 2 +- Lib/ldapurl.py | 2 +- Lib/ldif.py | 2 +- Lib/slapdtest/__init__.py | 2 +- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 500fa1e7..0491b6ef 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,20 @@ +Released 3.4.4 2022-11-17 + +Fixes: +* Reconnect race condition in ReconnectLDAPObject is now fixed +* Socket ownership is now claimed once we've passed it to libldap +* LDAP_set_option string formats are now compatible with Python 3.12 + +Doc/ +* Security Policy was created +* Broken article links are fixed now +* Bring Conscious Language improvements + +Infrastructure: +* Add testing and document support for Python 3.10, 3.11, and 3.12 + + +---------------------------------------------------------------- Released 3.4.3 2022-09-15 This is a minor release to bring back the removed OPT_X_TLS option. diff --git a/Lib/ldap/pkginfo.py b/Lib/ldap/pkginfo.py index 026e9101..18ead66c 100644 --- a/Lib/ldap/pkginfo.py +++ b/Lib/ldap/pkginfo.py @@ -1,6 +1,6 @@ """ meta attributes for packaging which does not import any dependencies """ -__version__ = '3.4.3' +__version__ = '3.4.4' __author__ = 'python-ldap project' __license__ = 'Python style' diff --git a/Lib/ldapurl.py b/Lib/ldapurl.py index 964076d3..b4dfd890 100644 --- a/Lib/ldapurl.py +++ b/Lib/ldapurl.py @@ -4,7 +4,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.3' +__version__ = '3.4.4' __all__ = [ # constants diff --git a/Lib/ldif.py b/Lib/ldif.py index ae1d643d..fa41321c 100644 --- a/Lib/ldif.py +++ b/Lib/ldif.py @@ -3,7 +3,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.3' +__version__ = '3.4.4' __all__ = [ # constants diff --git a/Lib/slapdtest/__init__.py b/Lib/slapdtest/__init__.py index 7ab7d2bd..7c410180 100644 --- a/Lib/slapdtest/__init__.py +++ b/Lib/slapdtest/__init__.py @@ -4,7 +4,7 @@ See https://www.python-ldap.org/ for details. """ -__version__ = '3.4.3' +__version__ = '3.4.4' from slapdtest._slapdtest import SlapdObject, SlapdTestCase, SysLogHandler from slapdtest._slapdtest import requires_ldapi, requires_sasl, requires_tls From ac5d051ec3bc3dee700ebbe3c1ba68f54fc39bc5 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Mon, 27 Nov 2023 21:52:26 +0200 Subject: [PATCH 34/41] Update link to unofficial Windows binary builds (#524) --- Doc/installing.rst | 4 ++-- Doc/spelling_wordlist.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/installing.rst b/Doc/installing.rst index e4518c11..6627ce5d 100644 --- a/Doc/installing.rst +++ b/Doc/installing.rst @@ -63,8 +63,8 @@ to get up to date information which versions are available. Windows ------- -Unofficial packages for Windows are available on -`Christoph Gohlke's page `_. +Unofficial binary builds for Windows are provided by Christoph Gohlke, available at +`python-ldap-build `_. `FreeBSD `_ diff --git a/Doc/spelling_wordlist.txt b/Doc/spelling_wordlist.txt index e6c2aedd..8cdd9f16 100644 --- a/Doc/spelling_wordlist.txt +++ b/Doc/spelling_wordlist.txt @@ -25,6 +25,7 @@ changeNumber changesOnly changeType changeTypes +Christoph cidict clientctrls conf @@ -56,6 +57,7 @@ filterstr filterStr formatOID func +Gohlke GPG Heimdal hostport From 10985e38902d170402acdfe6fabece5db70437cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Bourgault?= Date: Thu, 22 Feb 2024 08:19:11 +0100 Subject: [PATCH 35/41] docs: add missing negation in contributing.rst (#552) Current description contains a sentence that miss a negative form, contradicting previous sentence and leaving the reader with an ambiguity. --- Doc/contributing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/contributing.rst b/Doc/contributing.rst index bbaab491..6ef8a5a8 100644 --- a/Doc/contributing.rst +++ b/Doc/contributing.rst @@ -19,7 +19,7 @@ Communication Always keep in mind that python-ldap is developed and maintained by volunteers. We're happy to share our work, and to work with you to make the library better, -but (until you pay someone), there's obligation to provide assistance. +but (until you pay someone), there's no obligation to provide assistance. So, keep it friendly, respectful, and supportive! From 06fdd3dc4d3da82afa8d445cb8f1e8842c824236 Mon Sep 17 00:00:00 2001 From: RafaelWO <38643099+RafaelWO@users.noreply.github.com> Date: Tue, 27 Feb 2024 18:58:54 +0100 Subject: [PATCH 36/41] Update docs on installation requirements (#548) Separate building and testing requirements for Debian --- Doc/installing.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Doc/installing.rst b/Doc/installing.rst index 6627ce5d..03e7a295 100644 --- a/Doc/installing.rst +++ b/Doc/installing.rst @@ -143,10 +143,15 @@ Packages for building:: Debian ------ +Packages for building:: + + # apt-get install build-essential ldap-utils \ + libldap2-dev libsasl2-dev + Packages for building and testing:: - # apt-get install build-essential python3-dev \ - libldap2-dev libsasl2-dev slapd ldap-utils tox \ + # apt-get install build-essential ldap-utils \ + libldap2-dev libsasl2-dev slapd python3-dev tox \ lcov valgrind .. note:: From a58282adbc6b1f5f9755458227e6bb8667b72f6b Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount Date: Mon, 22 Apr 2024 22:18:09 +0000 Subject: [PATCH 37/41] Fixes #565 - Use name values instead of raw decimal Use the name values for result types in syncrepl.py rather than the raw decimal values. Signed-off-by: Quanah Gibson-Mount --- Lib/ldap/syncrepl.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/ldap/syncrepl.py b/Lib/ldap/syncrepl.py index 1708b468..fd0c1285 100644 --- a/Lib/ldap/syncrepl.py +++ b/Lib/ldap/syncrepl.py @@ -12,6 +12,7 @@ from ldap.pkginfo import __version__, __author__, __license__ from ldap.controls import RequestControl, ResponseControl, KNOWN_RESPONSE_CONTROLS +from ldap import RES_SEARCH_RESULT, RES_SEARCH_ENTRY, RES_INTERMEDIATE __all__ = [ 'SyncreplConsumer', @@ -407,7 +408,7 @@ def syncrepl_poll(self, msgid=-1, timeout=None, all=0): all=0, ) - if type == 101: + if type == RES_SEARCH_RESULT: # search result. This marks the end of a refreshOnly session. # look for a SyncDone control, save the cookie, and if necessary # delete non-present entries. @@ -420,7 +421,7 @@ def syncrepl_poll(self, msgid=-1, timeout=None, all=0): return False - elif type == 100: + elif type == RES_SEARCH_ENTRY: # search entry with associated SyncState control for m in msg: dn, attrs, ctrls = m @@ -439,7 +440,7 @@ def syncrepl_poll(self, msgid=-1, timeout=None, all=0): self.syncrepl_set_cookie(c.cookie) break - elif type == 121: + elif type == RES_INTERMEDIATE: # Intermediate message. If it is a SyncInfoMessage, parse it for m in msg: rname, resp, ctrls = m From 8b27db3d605974fc308b3b52ec464e354dcbafa0 Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Thu, 10 Oct 2024 22:55:29 -0700 Subject: [PATCH 38/41] Add support for Python 3.13 (#576) Update GitHub Actions. Explicitly install python3-setuptools for Tox env runs on Fedora. --- .github/workflows/ci.yml | 4 +++- .github/workflows/tox-fedora.yml | 5 +++-- setup.py | 1 + tox.ini | 5 ++++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37843f31..2f835d76 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,9 @@ jobs: - "3.10" - "3.11" - "3.12" + - "3.13" - "pypy3.9" + - "pypy3.10" image: - "ubuntu-22.04" include: @@ -43,7 +45,7 @@ jobs: - name: Disable AppArmor run: sudo aa-disable /usr/sbin/slapd - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} allow-prereleases: true diff --git a/.github/workflows/tox-fedora.yml b/.github/workflows/tox-fedora.yml index b86303fe..4c4c18f0 100644 --- a/.github/workflows/tox-fedora.yml +++ b/.github/workflows/tox-fedora.yml @@ -9,7 +9,7 @@ jobs: tox_test: name: Tox env "${{matrix.tox_env}}" on Fedora steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run Tox tests uses: fedora-python/tox-github-action@main with: @@ -17,7 +17,7 @@ jobs: dnf_install: > @c-development openldap-devel python3-devel openldap-servers openldap-clients lcov clang-analyzer valgrind - enchant + enchant python3-setuptools strategy: matrix: tox_env: @@ -28,6 +28,7 @@ jobs: - py310 - py311 - py312 + - py313 - c90-py36 - c90-py37 - py3-nosasltls diff --git a/setup.py b/setup.py index dbf66a04..8e7963a1 100644 --- a/setup.py +++ b/setup.py @@ -93,6 +93,7 @@ class OpenLDAP2: 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', # Note: when updating Python versions, also change tox.ini and .github/workflows/* 'Topic :: Database', diff --git a/tox.ini b/tox.ini index beade024..22752067 100644 --- a/tox.ini +++ b/tox.ini @@ -17,10 +17,12 @@ python = 3.10: py310 3.11: py311 3.12: py312 + 3.13: py313 pypy3.9: pypy3.9 + pypy3.10: pypy3.10 [testenv] -deps = +deps = setuptools passenv = WITH_GCOV # - Enable BytesWarning # - Turn all warnings into exceptions. @@ -98,6 +100,7 @@ deps = markdown sphinx sphinxcontrib-spelling + setuptools commands = {envpython} setup.py check --restructuredtext --metadata --strict {envpython} -m markdown README -f {envtmpdir}/README.html From 326f8708ca6d6fff36893a38f38b645bed9c5e6f Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Fri, 11 Oct 2024 08:16:27 -0700 Subject: [PATCH 39/41] Deprecate Pagure repo (#579) --- Doc/contributing.rst | 7 +------ Doc/spelling_wordlist.txt | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Doc/contributing.rst b/Doc/contributing.rst index 6ef8a5a8..de63a2e3 100644 --- a/Doc/contributing.rst +++ b/Doc/contributing.rst @@ -72,9 +72,6 @@ If you're used to open-source Python development with Git, here's the gist: .. _the bug tracker: https://github.com/python-ldap/python-ldap/issues .. _tox: https://tox.readthedocs.io/en/latest/ -Or, if you prefer to avoid closed-source services: - -* ``git clone https://pagure.io/python-ldap`` * Send bug reports and patches to the mailing list. * Run tests with `tox`_; ignore Python interpreters you don't have locally. * Read the documentation directly at `Read the Docs`_. @@ -203,8 +200,6 @@ remember: * Consider making the summary line suitable for the CHANGES document, and starting it with a prefix like ``Lib:`` or ``Tests:``. -* Push to Pagure as well. - If you have good reason to break the “rules”, go ahead and break them, but mention why. @@ -224,7 +219,7 @@ If you are tasked with releasing python-ldap, remember to: * Run ``python setup.py sdist``, and smoke-test the resulting package (install in a clean virtual environment, import ``ldap``). * Create GPG-signed Git tag: ``git tag -s python-ldap-{version}``. - Push it to GitHub and Pagure. + Push it to GitHub. * Release the ``sdist`` on PyPI. * Announce the release on the mailing list. Mention the Git hash. diff --git a/Doc/spelling_wordlist.txt b/Doc/spelling_wordlist.txt index 8cdd9f16..e2150d9a 100644 --- a/Doc/spelling_wordlist.txt +++ b/Doc/spelling_wordlist.txt @@ -100,7 +100,6 @@ oc oid oids OpenLDAP -Pagure postalAddress pre previousDN From e628f1582b46269ba6c31e1e3ee8a952cb32bb7d Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Tue, 28 Jan 2025 14:26:58 -0800 Subject: [PATCH 40/41] Deprecate EOL Python 3.6, 3.7, 3.8 versions --- .github/workflows/ci.yml | 9 ++------- .github/workflows/tox-fedora.yml | 7 +------ pyproject.toml | 4 ---- setup.py | 5 +---- tox.ini | 7 ++----- 5 files changed, 6 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f835d76..06d0b2ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ --- name: CI -on: +on: push: pull_request: schedule: @@ -20,8 +20,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.7" - - "3.8" - "3.9" - "3.10" - "3.11" @@ -29,11 +27,8 @@ jobs: - "3.13" - "pypy3.9" - "pypy3.10" - image: + image: - "ubuntu-22.04" - include: - - python-version: "3.6" - image: "ubuntu-20.04" steps: - name: Checkout uses: "actions/checkout@v4" diff --git a/.github/workflows/tox-fedora.yml b/.github/workflows/tox-fedora.yml index 4c4c18f0..bc6f45c5 100644 --- a/.github/workflows/tox-fedora.yml +++ b/.github/workflows/tox-fedora.yml @@ -21,20 +21,15 @@ jobs: strategy: matrix: tox_env: - - py36 - - py37 - - py38 - py39 - py310 - py311 - py312 - py313 - - c90-py36 - - c90-py37 - py3-nosasltls - py3-trace - pypy3 - doc # Use GitHub's Linux Docker host - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 diff --git a/pyproject.toml b/pyproject.toml index dda8dbc1..75f7c06a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,3 @@ -[tool.black] -line-length = 88 -target-version = ['py36', 'py37', 'py38'] - [tool.isort] line_length=88 known_first_party=['ldap', '_ldap', 'ldapurl', 'ldif', 'slapdtest'] diff --git a/setup.py b/setup.py index 8e7963a1..ea7364cd 100644 --- a/setup.py +++ b/setup.py @@ -86,9 +86,6 @@ class OpenLDAP2: 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', @@ -160,6 +157,6 @@ class OpenLDAP2: 'pyasn1_modules >= 0.1.5', ], zip_safe=False, - python_requires='>=3.6', + python_requires='>=3.9', test_suite = 'Tests', ) diff --git a/tox.ini b/tox.ini index 22752067..0b284a4e 100644 --- a/tox.ini +++ b/tox.ini @@ -5,15 +5,12 @@ [tox] # Note: when updating Python versions, also change setup.py and .github/worlflows/* -envlist = py{36,37,38,39,310,311,312},c90-py{36,37},py3-nosasltls,doc,py3-trace,pypy3.9 +envlist = py{39,310,311,312},py3-nosasltls,doc,py3-trace,pypy3.9 minver = 1.8 [gh-actions] python = - 3.6: py36 - 3.7: py37 - 3.8: py38, doc, py3-nosasltls - 3.9: py39, py3-trace + 3.9: py39, py3-trace, doc, py3-nosasltls 3.10: py310 3.11: py311 3.12: py312 From 30b24d5673095fecc73f652cfa41efc6208f9d72 Mon Sep 17 00:00:00 2001 From: Jiayu Hu <86949267+JennyHo5@users.noreply.github.com> Date: Sun, 13 Jul 2025 01:25:03 -0400 Subject: [PATCH 41/41] Fix typo (#584) The cookie is saved with key `cookie` intead of `ldap_cookie` in the `self.__data` dict --- Demo/pyasn1/syncrepl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Demo/pyasn1/syncrepl.py b/Demo/pyasn1/syncrepl.py index f1f24e19..754b237a 100644 --- a/Demo/pyasn1/syncrepl.py +++ b/Demo/pyasn1/syncrepl.py @@ -76,7 +76,7 @@ def syncrepl_entry(self, dn, attributes, uuid): logger.debug('Detected %s of entry %r', change_type, dn) # If we have a cookie then this is not our first time being run, # so it must be a change - if 'ldap_cookie' in self.__data: + if 'cookie' in self.__data: self.perform_application_sync(dn, attributes, previous_attributes) def syncrepl_delete(self,uuids): @@ -98,7 +98,7 @@ def syncrepl_present(self,uuids,refreshDeletes=False): deletedEntries = [ uuid for uuid in self.__data.keys() - if uuid not in self.__presentUUIDs and uuid != 'ldap_cookie' + if uuid not in self.__presentUUIDs and uuid != 'cookie' ] self.syncrepl_delete( deletedEntries ) # Phase is now completed, reset the list pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy