diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37843f31..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,18 +20,15 @@ jobs: fail-fast: false matrix: python-version: - - "3.7" - - "3.8" - "3.9" - "3.10" - "3.11" - "3.12" + - "3.13" - "pypy3.9" - image: + - "pypy3.10" + image: - "ubuntu-22.04" - include: - - python-version: "3.6" - image: "ubuntu-20.04" steps: - name: Checkout uses: "actions/checkout@v4" @@ -43,7 +40,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..bc6f45c5 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,23 +17,19 @@ 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: - - py36 - - py37 - - py38 - py39 - py310 - py311 - py312 - - c90-py36 - - c90-py37 + - py313 - 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/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/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 diff --git a/Doc/contributing.rst b/Doc/contributing.rst index bbaab491..de63a2e3 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! @@ -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/installing.rst b/Doc/installing.rst index e4518c11..03e7a295 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 `_ @@ -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:: diff --git a/Doc/spelling_wordlist.txt b/Doc/spelling_wordlist.txt index e6c2aedd..e2150d9a 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 @@ -98,7 +100,6 @@ oc oid oids OpenLDAP -Pagure postalAddress pre previousDN 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/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 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 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..71fac73e 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 @@ -276,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", @@ -293,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) @@ -315,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. @@ -521,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 */ @@ -572,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 @@ -730,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 * @@ -757,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)) @@ -809,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 @@ -858,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 @@ -912,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 */ @@ -958,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 */ @@ -1015,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 */ @@ -1065,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 */ @@ -1281,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) */ @@ -1451,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 */ @@ -1502,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/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..f0a0da94 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 */ @@ -107,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); @@ -131,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/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..cb3f58fb 100644 --- a/Modules/ldapmodule.c +++ b/Modules/ldapmodule.c @@ -1,17 +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" - -#if PY_MAJOR_VERSION >= 3 -PyMODINIT_FUNC PyInit__ldap(void); -#else -PyMODINIT_FUNC init_ldap(void); -#endif +#include "pythonldap.h" #define _STR(x) #x #define STR(x) _STR(x) @@ -33,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); @@ -78,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/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..4577b075 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) @@ -373,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/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..7703af5e --- /dev/null +++ b/Modules/pythonldap.h @@ -0,0 +1,131 @@ +/* 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 + +#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/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 6da3f491..ea7364cd 100644 --- a/setup.py +++ b/setup.py @@ -86,13 +86,11 @@ 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', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', # Note: when updating Python versions, also change tox.ini and .github/workflows/* 'Topic :: Database', @@ -117,15 +115,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, @@ -166,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 beade024..0b284a4e 100644 --- a/tox.ini +++ b/tox.ini @@ -5,22 +5,21 @@ [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 + 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 +97,7 @@ deps = markdown sphinx sphinxcontrib-spelling + setuptools commands = {envpython} setup.py check --restructuredtext --metadata --strict {envpython} -m markdown README -f {envtmpdir}/README.html 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